[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing\n\n## Project Scope\n\nThe Electron.NET project ultimately tries to provide a framework for developing cross-platform client applications on the basis of .NET and Electron. Anything that is related to this goal will be considered. The project aims to be as close to Electron with .NET as a basis as possible. If your contribution does not reflect that goal, the chances of accepting it are limited.\n\n## Code License\n\nThis is an open source project falling under the [MIT License](../LICENSE). By using, distributing, or contributing to this project, you accept and agree that all code within the Electron.NET project and its libraries are licensed under MIT license.\n\n## Becoming a Contributor\n\nUsually appointing someone as a contributor follows this process:\n\n1. An individual contributes actively via discussions (reporting bugs, giving feedback to existing or opening new issues) and / or pull requests\n2. The individual is either directly asked, invited or asks for contributor rights on the project\n3. The individual uses the contribution rights to sustain or increase the active contributions\n\nEvery contributor might have to sign the contributor's license agreement (CLA) to establish a legal trust between the project and its contributors.\n\n## Working on Electron.NET\n\n### Issue Discussion\n\nDiscussion of issues should be placed transparently in the issue tracker here on GitHub.\n\n* [General issues, bugs, new features](https://github.com/ElectronNET/Electron.NET/issues)\n* [General discussions, help, exchange of ideas](https://github.com/ElectronNET/Electron.NET/discussions)\n\n### Modifying the code\n\nElectron.NET and its libraries uses features from the latest versions of C# (e.g., C# 10). You will therefore need a C# compiler that is up for the job.\n\n1. Fork and clone the repo.\n2. First try to build the ElectronNET.Core library and see if you get the tests running.\n3. You will be required to resolve some dependencies via NuGet.\n\nThe build system of Electron.NET uses NUKE.\n\n### Code Conventions\n\nMost parts in the Electron.NET project are fairly straight forward. Among these are:\n\n* Always use statement blocks for control statements, e.g., in a for-loop, if-condition, ...\n* You may use a simple (throw) statement in case of enforcing contracts on argument\n* Be explicit about modifiers (some files follow an older convention of the code base, but we settled on the explicit style)\n\n### Development Workflow\n\n1. If no issue already exists for the work you'll be doing, create one to document the problem(s) being solved and self-assign.\n2. Otherwise please let us know that you are working on the problem. Regular status updates (e.g. \"still in progress\", \"no time anymore\", \"practically done\", \"pull request issued\") are highly welcome.\n3. Create a new branch—please don't work in the `main` branch directly. It is reserved for releases. We recommend naming the branch to match the issue being addressed (`feature/#777` or `issue-777`).\n4. Add failing tests for the change you want to make. Tests are crucial and should be taken from W3C (or other specification).\n5. Fix stuff. Always go from edge case to edge case.\n6. All tests should pass now. Also your new implementation should not break existing tests.\n7. Update the documentation to reflect any changes. (or document such changes in the original issue)\n8. Push to your fork or push your issue-specific branch to the main repository, then submit a pull request against `develop`.\n\nJust to illustrate the git workflow for Electron.NET a little bit more we've added the following graphs.\n\nInitially, Electron.NET starts at the `main` branch. This branch should contain the latest stable (or released) version.\n\nHere we now created a new branch called `develop`. This is the development branch.\n\nNow active work is supposed to be done. Therefore a new branch should be created. Let's create one:\n\n```sh\ngit checkout -b feature/#777\n```\n\nThere may be many of these feature branches. Most of them are also pushed to the server for discussion or synchronization.\n\n```sh\ngit push -u origin feature/#777\n```\n\nNow feature branches may be closed when they are done. Here we simply merge with the feature branch(es). For instance the following command takes the `feature/#777` branch from the server and merges it with the `develop` branch.\n\n```sh\ngit checkout develop\ngit pull\ngit pull origin feature/#777\ngit push\n```\n\nFinally, we may have all the features that are needed to release a new version of Electron.NET. Here we tag the release. For instance for the 1.0 release we use `v1.0`.\n\n```sh\ngit checkout main\ngit merge develop\ngit tag v1.0\n```\n\n(The last part is automatically performed by our CI system. Don't tag manually.)\n\n### Versioning\n\nThe rules of [semver](http://semver.org/) don't necessarily apply here, but we will try to stay quite close to them.\n\nPrior to version 1.0.0 we use the following scheme:\n\n1. MINOR versions for reaching a feature milestone potentially combined with dramatic API changes\n2. PATCH versions for refinements (e.g. performance improvements, bug fixes)\n\nAfter releasing version 1.0.0 the scheme changes to become:\n\n1. MAJOR versions at maintainers' discretion following significant changes to the codebase (e.g., API changes)\n2. MINOR versions for backwards-compatible enhancements (e.g., performance improvements)\n3. PATCH versions for backwards-compatible bug fixes (e.g., spec compliance bugs, support issues)\n\n#### Code style\n\nRegarding code style like indentation and whitespace, **follow the conventions you see used in the source already.** In general most of the [C# coding guidelines from Microsoft](https://msdn.microsoft.com/en-us/library/ff926074.aspx) are followed. This project prefers type inference with `var` to explicitly stating (redundant) information.\n\nIt is also important to keep a certain `async`-flow and to always use `ConfigureAwait(false)` in conjunction with an `await` expression.\n\n## Backwards Compatibility\n\nWe always try to remain backwards compatible beyond the currently supported versions of .NET.\n\nFor instance, in December 2025 there have been activity to remove .NET 6 support from the codebase. We rejected this. Key points:\n\n1. We have absolutely no need to drop `.net6` support. It doesn't hurt us in any way.\n2. Many are still using `.net6`, including Electron.NET (non-Core) users. It doesn't make sense to force them to update two things at the same time (.NET + Electron.NET).\n3. We MUST NOT and NEVER update `Microsoft.Build.Utilities.Core`. This will make Electron.NET stop working on older Visual Studio and MSBuild versions. There's are also no reasons to update it in the first place.\n\nIt's important to note that the Microsoft label of \"Out of support\" on .NET has almost no practical meaning. We've rarely (if ever) seen any bugs fixed in the same .NET version which mattered. The bugs that all new .NET versions have are much worse than mature .NET versions which are declared as \"out of support\". Keep in mind that the LTS matters most for active development / ongoing supported projects. If, e.g., a TV has been released a decade ago it most likely won't be patched. Still, you might want to deploy applications to it, which then naturally would involve being based on \"out of support\" versions of the framework.\n\nTL;DR: Unless there is a technical reason (e.g., a crucial new API not being available) we should not drop \"out of support\" .NET versions. At the time of writing (December 2025) the minimum supported .NET version remains at `.net6`.\n\n## Timeline\n\n**All of this information is related to ElectronNET.Core pre-v1!**\n\nWe pretty much release whenever we have something new (i.e., do fixes such as a 0.1.1, or add new features, such as a 0.2.0) quite quickly.\n\nWe will go for a 1.0.0 release of this as early as ~mid of January 2026 (unless we find some critical things or want to extend the beta phase for ElectronNET.Core). This should be sufficient time to get some user input and have enough experience to call it stable.\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [GregorBiswanger, FlorianRappl]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: https://donorbox.org/electron-net\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n<!-- Please search existing issues to avoid creating duplicates. -->\n\n<!-- Which version of Electron.NET CLI and API are you using? -->\n<!-- Please always try to use latest version before report. -->\n* **Version**: \n\n<!-- Which version of .NET Core and Node.js are you using (if applicable)? -->\n\n<!-- What target are you building for? -->\n* **Target**: \n\n<!-- Enter your issue details below this comment. -->\n<!-- If you want, you can donate to increase issue priority (https://donorbox.org/electron-net) -->\n\nSteps to Reproduce:\n\n1.\n2.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: Feature\nassignees: ''\n\n---\n\n<!-- Please search existing feature request to avoid creating duplicates. -->\n\n<!-- If you want, you can donate to increase feature request priority (https://donorbox.org/electron-net) -->\n<!-- Describe the feature you'd like. -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "content": "---\nname: Question\nabout: The issue tracker is not for questions. Please ask questions on https://stackoverflow.com/questions/tagged/electron.net\n  or via chat in https://gitter.im/ElectronNET/community.\ntitle: ''\nlabels: question\nassignees: ''\n\n---\n\n🚨 The issue tracker is not for questions 🚨\n\nThe issue tracker is not for questions. Please ask questions on https://stackoverflow.com/questions/tagged/electron.net or via chat in https://gitter.im/ElectronNET/community.\n"
  },
  {
    "path": ".github/workflows/Build and Publish.yml",
    "content": "name: Build and Publish\n\non: [push]\n\nenv:\n  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n  NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}\n\nconcurrency:\n  group: build-publish-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  Integration-Tests:\n    uses: ./.github/workflows/integration-tests.yml\n    name: '1'\n\n  Publish:\n    needs: [Integration-Tests]\n    runs-on: windows-latest\n    timeout-minutes: 10\n    name: '2 / Publish'\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Setup dotnet\n      uses: actions/setup-dotnet@v4\n      with:\n        dotnet-version: |\n          6.0.x\n          8.0.x\n          10.0.x\n\n    - name: Build\n      run: |\n        if ($env:GITHUB_REF -eq \"refs/heads/main\") {\n          .\\build.ps1 -Target Publish\n        } elseif ($env:GITHUB_REF -eq \"refs/heads/develop\") {\n          .\\build.ps1 -Target PrePublish\n        } else {\n          .\\build.ps1\n        }\n"
  },
  {
    "path": ".github/workflows/PR Validation.yml",
    "content": "name: PR Validation\n\non: [pull_request]\n\nconcurrency:\n  group: pr-validation-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  Whitespace-Check:\n    uses: ./.github/workflows/trailing-whitespace-check.yml\n    secrets: inherit\n    name: '1'\n    \n  Tests:\n    needs: Whitespace-Check\n    uses: ./.github/workflows/integration-tests.yml\n    secrets: inherit\n    name: '2'\n\n  build:\n    needs: [Whitespace-Check, Tests]\n    runs-on: windows-latest\n    timeout-minutes: 10\n    name: '3 / Build'\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Setup dotnet\n      uses: actions/setup-dotnet@v4\n      with:\n        dotnet-version: |\n          6.0.x\n          8.0.x\n          10.0.x\n\n    - name: Build\n      run: .\\build.ps1\n"
  },
  {
    "path": ".github/workflows/integration-tests.yml",
    "content": "name: Tests\n\non:\n  workflow_call:\n\nconcurrency:\n  group: integration-tests-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  tests:\n    name: ${{ matrix.os }} API-${{ matrix.electronVersion }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-22.04, ubuntu-24.04, windows-2022, windows-2025, macos-14, macos-15-intel, macos-26]\n        electronVersion: ['30.4.0', '38.2.2']\n        include:\n          - os: ubuntu-22.04\n            rid: linux-x64\n          - os: ubuntu-24.04\n            rid: linux-x64\n          - os: windows-2022\n            rid: win-x64\n          - os: windows-2025\n            rid: win-x64\n          - os: macos-14\n            rid: osx-arm64\n          - os: macos-15-intel\n            rid: osx-x64\n          - os: macos-26\n            rid: osx-arm64\n\n    env:\n      DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1\n      DOTNET_NOLOGO: 1\n      CI: true\n      ELECTRON_ENABLE_LOGGING: 1\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Random delay (0-20 seconds)\n        shell: bash\n        run: |\n          DELAY=$((RANDOM % 21))\n          echo \"Waiting for $DELAY seconds...\"\n          sleep $DELAY\n\n      - name: Setup .NET\n        uses: actions/setup-dotnet@v4\n        with:\n          dotnet-version: '10.0.x'\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: '22'\n\n      - name: Restore\n        run: dotnet restore -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} -p:ElectronVersion=${{ matrix.electronVersion }} src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj\n\n      - name: Build\n        run: dotnet build --no-restore -c Release -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} -p:ElectronVersion=${{ matrix.electronVersion }} src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj\n\n      - name: Install Linux GUI dependencies\n        if: runner.os == 'Linux'\n        run: |\n          set -e\n          sudo apt-get update\n          . /etc/os-release\n          if [ \"$VERSION_ID\" = \"24.04\" ]; then ALSA_PKG=libasound2t64; else ALSA_PKG=libasound2; fi\n          echo \"Using ALSA package: $ALSA_PKG\"\n          sudo apt-get install -y xvfb \\\n            libgtk-3-0 libnss3 libgdk-pixbuf-2.0-0 libdrm2 libgbm1 libxss1 libxtst6 libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 libx11-xcb1 \"$ALSA_PKG\"\n\n      - name: Run tests (Linux)\n        if: runner.os == 'Linux'\n        continue-on-error: true\n        run: |\n          mkdir -p test-results\n          xvfb-run -a dotnet test src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj \\\n            -c Release --no-build -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} -p:ElectronVersion=${{ matrix.electronVersion }} \\\n            --logger \"trx;LogFileName=${{ matrix.os }}-electron-${{ matrix.electronVersion }}.trx\" \\\n            --logger \"console;verbosity=detailed\" \\\n            --results-directory test-results\n\n      - name: Run tests (Windows)\n        if: runner.os == 'Windows'\n        continue-on-error: true\n        run: |\n          New-Item -ItemType Directory -Force -Path test-results | Out-Null\n          dotnet test src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj -c Release --no-build -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} -p:ElectronVersion=${{ matrix.electronVersion }} --logger \"trx;LogFileName=${{ matrix.os }}-electron-${{ matrix.electronVersion }}.trx\" --logger \"console;verbosity=detailed\" --results-directory test-results\n\n      - name: Run tests (macOS)\n        if: runner.os == 'macOS'\n        continue-on-error: true\n        run: |\n          mkdir -p test-results\n          dotnet test src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj -c Release --no-build -r ${{ matrix.rid }} -p:RuntimeIdentifier=${{ matrix.rid }} -p:ElectronVersion=${{ matrix.electronVersion }} --logger \"trx;LogFileName=${{ matrix.os }}-electron-${{ matrix.electronVersion }}.trx\" --logger \"console;verbosity=detailed\" --results-directory test-results\n\n      - name: Upload raw test results\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: test-results-${{ matrix.os }}-electron-${{ matrix.electronVersion }}\n          path: test-results/*.trx\n          retention-days: 7\n\n  summary:\n    name: Test Results\n    runs-on: ubuntu-24.04\n    if: always()\n    needs: [tests]\n\n    permissions:\n      actions: read\n      contents: read\n      checks: write\n      pull-requests: write\n\n    steps:\n      - name: Download all test results\n        uses: actions/download-artifact@v4\n        with:\n          path: test-results\n\n      - name: Setup .NET (for CTRF conversion)\n        uses: actions/setup-dotnet@v4\n        with:\n          dotnet-version: '10.0.x'\n\n      - name: Install CTRF TRX→CTRF converter (dotnet tool)\n        run: |\n          dotnet new tool-manifest\n          dotnet tool install DotnetCtrfJsonReporter --local\n\n      - name: Convert TRX → CTRF and clean names (filePath=OS|Electron X.Y.Z)\n        shell: bash\n        run: |\n          set -euo pipefail\n          mkdir -p ctrf\n          shopt -s globstar nullglob\n          conv=0\n          for trx in test-results/**/*.trx; do\n            base=\"$(basename \"$trx\" .trx)\"  # e.g. ubuntu-22.04-electron-30.4.0\n            os=\"${base%%-electron-*}\"\n            electron=\"${base#*-electron-}\"\n            label=\"$os|Electron $electron\"\n            outdir=\"ctrf/${label}\"\n            mkdir -p \"$outdir\"\n            out=\"${outdir}/ctrf-report.json\"\n\n            dotnet tool run DotnetCtrfJsonReporter -p \"$trx\" -d \"$outdir\" -f \"ctrf-report.json\"\n\n            jq --arg fp \"$label\" '.results.tests |= map(.filePath = $fp)' \"$out\" > \"${out}.tmp\" && mv \"${out}.tmp\" \"$out\"\n\n            echo \"Converted & normalized $trx -> $out\"\n            conv=$((conv+1))\n          done\n          echo \"Processed $conv TRX file(s)\"\n\n      - name: Publish Test Report\n        if: always()\n        uses: ctrf-io/github-test-reporter@v1\n        with:\n          report-path: 'ctrf/**/*.json'\n          summary: true\n          pull-request: false\n          status-check: false\n          status-check-name: 'Integration Tests'\n          use-suite-name: true\n          update-comment: true\n          always-group-by: true\n          overwrite-comment: true\n          exit-on-fail: true\n          group-by: 'suite'\n          upload-artifact: true\n          fetch-previous-results: true\n          summary-report: false\n          summary-delta-report: true\n          github-report: true\n          test-report: false\n          test-list-report: false\n          failed-report: true\n          failed-folded-report: false\n          skipped-report: true\n          suite-folded-report: true\n          suite-list-report: false\n          file-report: true\n          previous-results-report: true\n          insights-report: true\n          flaky-report: true\n          flaky-rate-report: true\n          fail-rate-report: false\n          slowest-report: false\n          report-order: 'summary-delta-report,failed-report,skipped-report,suite-folded-report,file-report,previous-results-report,github-report'\n        env:\n          GITHUB_TOKEN: ${{ github.token }}\n\n      - name: Save PR Number\n        if: github.event_name == 'pull_request'\n        run: echo \"PR_NUMBER=${{ github.event.pull_request.number }}\" >> $GITHUB_ENV\n\n      - name: Write PR Number to File\n        if: github.event_name == 'pull_request'\n        run: echo \"$PR_NUMBER\" > pr_number.txt\n        shell: bash\n\n      - name: Upload PR Number Artifact\n        if: github.event_name == 'pull_request'\n        uses: actions/upload-artifact@v4\n        with:\n          name: pr_number\n          path: pr_number.txt\n\n      - name: Summary\n        run: echo \"All matrix test jobs completed.\"\n"
  },
  {
    "path": ".github/workflows/pr-comment.yml",
    "content": "name: Create PR Comments\n\non:\n  workflow_run:\n    workflows: [ \"PR Validation\" ]\n    types: [completed]\n\npermissions:\n  contents: read\n  actions: read\n  pull-requests: write\n\njobs:\n  pr-comment:\n    name: Post Test Result as PR comment\n    runs-on: ubuntu-24.04\n    if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion != 'cancelled'\n\n    steps:\n      - name: Download CTRF artifact\n        uses: dawidd6/action-download-artifact@v8\n        with:\n          github_token: ${{ github.token }}\n          run_id: ${{ github.event.workflow_run.id }}\n          name: ctrf-report\n          path: ctrf\n\n      - name: Download PR Number Artifact\n        uses: dawidd6/action-download-artifact@v8\n        with:\n          github_token: ${{ github.token }}\n          run_id: ${{ github.event.workflow_run.id }}\n          name: pr_number\n          path: pr_number\n\n      - name: Read PR Number\n        run: |\n          set -Eeuo pipefail\n          FILE='pr_number/pr_number.txt'\n\n          # Ensure file exists\n          if [ ! -f \"$FILE\" ] || [ -L \"$FILE\" ]; then\n            echo \"Error: $FILE is missing or is not a regular file.\" >&2\n            exit 1\n          fi\n\n          # Chec file size\n          if [ \"$(wc -c < \"$FILE\" | tr -d ' ')\" -gt 200 ]; then\n            echo \"Error: $FILE is too large.\" >&2\n            exit 1\n          fi\n\n          # Read first line\n          PR_NUMBER=\"\"\n          IFS= read -r PR_NUMBER < \"$FILE\" || true\n\n          # Validate whether it's a number\n          if ! [[ \"$PR_NUMBER\" =~ ^[0-9]{1,10}$ ]]; then\n            echo \"Error: PR_NUMBER is not a valid integer on the first line.\" >&2\n            exit 1\n          fi\n\n          printf 'PR_NUMBER=%s\\n' \"$PR_NUMBER\" >> \"$GITHUB_ENV\"\n\n      - name: Post PR Comment\n        uses: ctrf-io/github-test-reporter@v1\n        with:\n          report-path: 'ctrf/**/*.json'\n          issue: ${{ env.PR_NUMBER }}\n\n          summary: true\n          pull-request: true\n          use-suite-name: true\n          update-comment: true\n          always-group-by: true\n          overwrite-comment: true\n          upload-artifact: false\n\n          pull-request-report: true\n        env:\n          GITHUB_TOKEN: ${{ github.token }}\n"
  },
  {
    "path": ".github/workflows/publish-wiki.yml",
    "content": "name: Publish wiki\non:\n  push:\n    branches: [electronnet_core, main]\n  workflow_dispatch:\nconcurrency:\n  group: publish-wiki\n  cancel-in-progress: true\npermissions:\n  contents: write\njobs:\n  publish-wiki:\n    runs-on: windows-latest\n    steps:\n      - uses: actions/checkout@v3\n      - name: Remove level 1 headings from Markdown files\n        shell: bash\n        run: |\n          find docs/ -name '*.md' -exec sed -i '1d' {} \\;\n      - name: Move all files to root folder\n        shell: bash\n        run: |\n          mv docs/*/* docs/\n      - name: Delete unwanted files\n        shell: bash\n        run: |\n          # rm docs/*.xlsm\n          # rm docs/*.pptx\n          rm docs/*.shproj\n      - name: Stripping file extensions....\n        uses: softworkz/strip-markdown-extensions-from-links-action@main\n        with:\n          path: ./docs/\n      - name: Copy Changelog\n        shell: bash\n        run: |\n          cp Changelog.md docs/RelInfo/ 2>/dev/null || true\n      - name: Copy images to wiki/wiki folder\n        shell: bash\n        run: |\n          mkdir docs/wiki\n          cp docs/*.svg docs/wiki/ 2>/dev/null || true\n          cp docs/*.png docs/wiki/ 2>/dev/null || true\n          cp docs/*.jpg docs/wiki/ 2>/dev/null || true\n          cp docs/*.gif docs/wiki/ 2>/dev/null || true\n          cp docs/*.mp4 docs/wiki/ 2>/dev/null || true\n      - name: Commit and push changes\n        run: |\n          git config --global user.name \"GitHub Action\"\n          git config --global user.email \"action@github.com\"\n          git add -A\n          git commit -m \"Automatically update Markdown files\" || echo \"No changes to commit\"\n      - uses: Andrew-Chen-Wang/github-wiki-action@v4.4.0\n        with:\n          path: docs/\n          ignore: |\n            '**/*.xlsm'\n            '**/*.pptx'\n            '**/*.shproj'\n"
  },
  {
    "path": ".github/workflows/retry-test-jobs.yml",
    "content": "name: Tests auto-rerun\n\non:\n  workflow_run:\n    workflows: [ \"PR Validation\", \"Build and Publish\" ]\n    types: [ completed ]\n\njobs:\n  rerun-failed-matrix-jobs-once:\n    if: >\n      ${{\n        github.event.workflow_run.conclusion == 'failure' &&\n        github.event.workflow_run.run_attempt == 1\n      }}\n    runs-on: ubuntu-24.04\n\n    permissions:\n      actions: write\n      contents: read\n\n    steps:\n      - name: Decide whether to rerun (only if matrix jobs failed)\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          REPO: ${{ github.repository }}\n          RUN_ID: ${{ github.event.workflow_run.id }}\n        run: |\n          echo \"Inspecting jobs of workflow run $RUN_ID in $REPO\"\n\n          jobs_json=\"$(gh api -R $REPO repos/$REPO/actions/runs/$RUN_ID/jobs)\"\n\n          echo \"Jobs and conclusions:\"\n          echo \"$jobs_json\" | jq '.jobs[] | {name: .name, conclusion: .conclusion}'\n\n          failed_matrix_jobs=$(echo \"$jobs_json\" | jq -r '\n            [ .jobs[]\n              | select(.conclusion == \"failure\"\n                       and (.name | contains(\" API-\")))\n            ]\n            | length // 0\n          ')\n          failed_matrix_jobs=${failed_matrix_jobs:-0}\n\n          if [ \"${failed_matrix_jobs}\" -gt 0 ]; then\n            echo \"Detected failing Integration Tests jobs – re-running failed jobs for this run.\"\n            gh run rerun -R \"$REPO\" \"$RUN_ID\" --failed\n          else\n            echo \"Only non-matrix jobs (like Test Results) failed – not auto-rerunning.\"\n          fi\n"
  },
  {
    "path": ".github/workflows/trailing-whitespace-check.yml",
    "content": "name: Whitespace Check\n\non:\n  workflow_call:\n\njobs:\n  check-whitespace:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n\n    steps:\n    - name: Checkout code\n      uses: actions/checkout@v4\n      with:\n        fetch-depth: 0\n\n    - name: Check for trailing whitespace\n      run: |\n        echo \"Checking for trailing whitespace in changed files...\"\n\n        # Get the base branch\n        BASE_SHA=\"${{ github.event.pull_request.base.sha }}\"\n        HEAD_SHA=\"${{ github.event.pull_request.head.sha }}\"\n\n        # Get list of changed files (excluding deleted files)\n        CHANGED_FILES=$(git diff --name-only --diff-filter=d \"$BASE_SHA\" \"$HEAD_SHA\")\n\n        if [ -z \"$CHANGED_FILES\" ]; then\n          echo \"No files to check.\"\n          exit 0\n        fi\n\n        # File patterns to check (text files)\n        PATTERNS=\"\\.cs$|\\.csproj$|\\.sln$|\\.ts$|\\.html$|\\.css$|\\.scss$\"\n\n        # Directories and file patterns to exclude\n        EXCLUDE_PATTERNS=\"(^|\\/)(\\.|node_modules|bin|obj|artifacts|packages|\\.vs|\\.nuke\\/temp)($|\\/)\"\n\n        ERRORS_FOUND=0\n        TEMP_FILE=$(mktemp)\n\n        while IFS= read -r file; do\n          # Skip if file doesn't exist (shouldn't happen with --diff-filter=d, but just in case)\n          if [ ! -f \"$file\" ]; then\n            continue\n          fi\n\n          # Check if file matches patterns to check\n          if ! echo \"$file\" | grep -qE \"$PATTERNS\"; then\n            continue\n          fi\n\n          # Check if file should be excluded\n          if echo \"$file\" | grep -qE \"$EXCLUDE_PATTERNS\"; then\n            continue\n          fi\n\n          # Find trailing whitespace lines, excluding XML doc placeholder lines that are exactly \"/// \" (one space)\n          MATCHES=$(grep -n '[[:space:]]$' \"$file\" | grep -vE '^[0-9]+:[[:space:]]*/// $' || true)\n\n          if [ -n \"$MATCHES\" ]; then\n            echo \"❌ Trailing whitespace found in: $file\"\n            echo \"$MATCHES\" | head -10\n            TOTAL=$(echo \"$MATCHES\" | wc -l)\n            if [ \"$TOTAL\" -gt 10 ]; then\n              echo \"   ... and $(($TOTAL - 10)) more lines\"\n            fi\n            echo \"1\" >> \"$TEMP_FILE\"\n          fi\n        done <<< \"$CHANGED_FILES\"\n\n        ERRORS_FOUND=$(wc -l < \"$TEMP_FILE\" 2>/dev/null || echo \"0\")\n        rm -f \"$TEMP_FILE\"\n\n        if [ \"$ERRORS_FOUND\" -gt 0 ]; then\n          echo \"\"\n          echo \"❌ Found trailing whitespace in $ERRORS_FOUND file(s).\"\n          echo \"Please remove trailing whitespace from the files listed above.\"\n          exit 1\n        else\n          echo \"✅ No trailing whitespace found in changed files.\"\n          exit 0\n        fi\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n!/artifacts/.gitkeep\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n#*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Mac Only settings file\n.DS_Store\n\n# Nuke build tool\n.nuke/temp\n/publish.cmd\n"
  },
  {
    "path": ".nuke/build.schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"definitions\": {\n    \"Host\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"AppVeyor\",\n        \"AzurePipelines\",\n        \"Bamboo\",\n        \"Bitbucket\",\n        \"Bitrise\",\n        \"GitHubActions\",\n        \"GitLab\",\n        \"Jenkins\",\n        \"Rider\",\n        \"SpaceAutomation\",\n        \"TeamCity\",\n        \"Terminal\",\n        \"TravisCI\",\n        \"VisualStudio\",\n        \"VSCode\"\n      ]\n    },\n    \"ExecutableTarget\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"Clean\",\n        \"Compile\",\n        \"Default\",\n        \"Package\",\n        \"PrePublish\",\n        \"Publish\",\n        \"PublishPackages\",\n        \"PublishPreRelease\",\n        \"PublishRelease\",\n        \"Restore\",\n        \"RunUnitTests\"\n      ]\n    },\n    \"Verbosity\": {\n      \"type\": \"string\",\n      \"description\": \"\",\n      \"enum\": [\n        \"Verbose\",\n        \"Normal\",\n        \"Minimal\",\n        \"Quiet\"\n      ]\n    },\n    \"NukeBuild\": {\n      \"properties\": {\n        \"Continue\": {\n          \"type\": \"boolean\",\n          \"description\": \"Indicates to continue a previously failed build attempt\"\n        },\n        \"Help\": {\n          \"type\": \"boolean\",\n          \"description\": \"Shows the help text for this build assembly\"\n        },\n        \"Host\": {\n          \"description\": \"Host for execution. Default is 'automatic'\",\n          \"$ref\": \"#/definitions/Host\"\n        },\n        \"NoLogo\": {\n          \"type\": \"boolean\",\n          \"description\": \"Disables displaying the NUKE logo\"\n        },\n        \"Partition\": {\n          \"type\": \"string\",\n          \"description\": \"Partition to use on CI\"\n        },\n        \"Plan\": {\n          \"type\": \"boolean\",\n          \"description\": \"Shows the execution plan (HTML)\"\n        },\n        \"Profile\": {\n          \"type\": \"array\",\n          \"description\": \"Defines the profiles to load\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"Root\": {\n          \"type\": \"string\",\n          \"description\": \"Root directory during build execution\"\n        },\n        \"Skip\": {\n          \"type\": \"array\",\n          \"description\": \"List of targets to be skipped. Empty list skips all dependencies\",\n          \"items\": {\n            \"$ref\": \"#/definitions/ExecutableTarget\"\n          }\n        },\n        \"Target\": {\n          \"type\": \"array\",\n          \"description\": \"List of targets to be invoked. Default is '{default_target}'\",\n          \"items\": {\n            \"$ref\": \"#/definitions/ExecutableTarget\"\n          }\n        },\n        \"Verbosity\": {\n          \"description\": \"Logging verbosity during build execution. Default is 'Normal'\",\n          \"$ref\": \"#/definitions/Verbosity\"\n        }\n      }\n    }\n  },\n  \"allOf\": [\n    {\n      \"properties\": {\n        \"CommonPropsFilePath\": {\n          \"type\": \"string\",\n          \"description\": \"common.props file path - to determine the configured version\"\n        },\n        \"Configuration\": {\n          \"type\": \"string\",\n          \"description\": \"Configuration to build - Default is 'Debug' (local) or 'Release' (server)\",\n          \"enum\": [\n            \"Debug\",\n            \"Release\"\n          ]\n        },\n        \"ReleaseNotesFilePath\": {\n          \"type\": \"string\",\n          \"description\": \"ReleaseNotesFilePath - To determine the lates changelog version\"\n        },\n        \"Solution\": {\n          \"type\": \"string\",\n          \"description\": \"Path to a solution file that is automatically loaded\"\n        }\n      }\n    },\n    {\n      \"$ref\": \"#/definitions/NukeBuild\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".nuke/parameters.json",
    "content": "{\n  \"$schema\": \"./build.schema.json\",\n  \"Solution\": \"src/ElectronNET.Lean.sln\"\n}"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n   // Use IntelliSense to find out which attributes exist for C# debugging\n   // Use hover for the description of the existing attributes\n   // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md\n   \"version\": \"0.2.0\",\n   \"configurations\": [\n        {\n            \"name\": \".NET Core Launch (console)\",\n            \"type\": \"coreclr\",\n            \"request\": \"launch\",\n            \"preLaunchTask\": \"build\",\n            // If you have changed target frameworks, make sure to update the program path.\n            \"program\": \"${workspaceRoot}/src/ElectronNET.CLI/bin/Debug/net8.0/dotnet-electronize.dll\",\n            \"args\": [],\n            \"cwd\": \"${workspaceRoot}/src/ElectronNET.CLI\",\n            // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window\n            \"console\": \"internalConsole\",\n            \"stopAtEntry\": false,\n            \"internalConsoleOptions\": \"openOnSessionStart\"\n        },\n        {\n            \"name\": \".NET Core Attach\",\n            \"type\": \"coreclr\",\n            \"request\": \"attach\",\n            \"processId\": \"${command:pickProcess}\"\n        }\n    ]\n}"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n  \"version\": \"2.0.0\",\n  \"command\": \"dotnet\",\n  \"args\": [],\n  \"tasks\": [\n    {\n      \"label\": \"build\",\n      \"type\": \"shell\",\n      \"command\": \"dotnet\",\n      \"args\": [\"build\", \"${workspaceRoot}/src/ElectronNET.CLI/ElectronNET.CLI.csproj\"],\n      \"problemMatcher\": \"$msCompile\",\n      \"group\": {\n        \"_id\": \"build\",\n        \"isDefault\": false\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "Changelog.md",
    "content": "# 0.4.1\n\n## ElectronNET.Core\n\n- Updated documentation for preload scripts (#1031) @AeonSake\n- Updated timeout for electron-builder (#1013) @softworkz\n- Updated disposal avoiding exceptions on teardown (#1026) @softworkz\n- Updated migration guide (#1015) @hilin\n- Fixed handling of `Center` property for windows (#1001)\n- Fixed false alarm for `ELECTRON001`, `ELECTRON008`, and `ELECTRON009` (#1012) @softworkz\n- Added missing methods on `Cookies` (#1000)\n- Added overload for `GetAllDisplaysAsync` with timeout (#1033) @softworkz\n- Added `OnBoundsChanged` event (#1014) @softworkz\n- Added new events for `ipcMain` (#1019) @DYH1319\n\n# 0.4.0\n\n## ElectronNET.Core\n\n- Fixed ElectronSingleInstance handling (#996) @softworkz\n- Fixed `PackageId` handling (#993) @softworkz\n- Added cross-platform npm restore and check mismatch on publish (#988) @softworkz\n\n# 0.3.1\n\n## ElectronNET.Core\n\n- Fixed issue transforming the project ID (#989, #990) @softworkz\n\n# 0.3.0\n\n## ElectronNET.Core\n\n- Updated infrastructure (#937, #939) @softworkz\n- Updated all model classes to Electron API 39.2 (#949) @softworkz\n- Fixed output path for `electron-builder` (#942) @softworkz\n- Fixed floating point display resolution (#944) @softworkz\n- Fixed error in case of missing electron-host-hook (#978)\n- Fixed previous API break using exposed `JsonElement` objects (#938) @softworkz\n- Fixed and improved several test cases (#962) @softworkz\n- Fixed startup of Electron.NET from VS Code Debug Adapter (#952)\n- Fixed the `BrowserWindowOptions` (#945) @softworkz\n- Fixed example for `AutoMenuHide` to reflect platform capabilities (#982) @markatosi\n- Added several migration checks for publishing (#966) @softworkz\n- Added more test runners for E2E tests (#950, #951) @agracio\n- Added dynamic updates for tray menu (#973) @davidroth\n- Added matrix tests with 6 runners and 2 electron version (#948) @softworkz\n- Added additional APIs for WebContents (#958) @agracio\n- Added documentation for MacOS package publish (#983) @markatosi\n- Added sample application for `ElectronHostHook` (#967) @adityashirsatrao007\n\n# 0.2.0\n\n## ElectronNET.Core\n\n- Updated dependencies (#930) @softworkz\n- Updated integration tests (#931) @softworkz\n- Updated `ElectronNET.Host` (#935) @softworkz\n- Removed transition period specific build configuration (#928) @softworkz\n- Added `IsRunningBlazor` option to `BrowserWindowOptions` (#926)\n- Added platform support attributes (#929) @softworkz\n\n# 0.1.0\n\n## ElectronNET.Core\n\n- Updated `PrintToPDFOptions` to also allow specifying the `PageSize` with an object (#769)\n- Updated splashscreen image to have 0 margin (#622)\n- Updated the IPC API w.r.t. naming and consistency (#905) @agracio\n- Updated the IPC bridge w.r.t. synchronization and thread-safety (#918) @agracio\n- Updated serialization to use `System.Text.Json` replacing `Newtonsoft.Json` (#917) @Denny09310\n- Fixed parameter handling for the `sendToIpcRenderer` function (#922) @softworkz\n- Fixed synchronization on removing event handlers (#921) @softworkz\n- Fixed creation of windows with `contextIsolation` enabled (#906) @NimbusFox\n- Fixed single instance behavior using the `ElectronSingleInstance` property (#901)\n- Fixed potential race conditions (#908) @softworkz\n- Added option to use `ElectronSplashScreen` with an HTML file (#799)\n- Added option to provide floating point value as aspect ratios with `SetAspectRatio` (#793)\n- Added option to provide `TitleBarOverlay` as an object (#911) @Denny09310\n- Added `TitleBarOverlay` property to `BrowserWindowOptions` (#909)\n- Added `RoundedCorners` property to `BrowserWindowOptions`\n- Added integration tests and robustness checks (#913) @softworkz\n- Added .NET 10 as an explicit target\n\n# 0.0.18\n\n## ElectronNET.Core\n\n### Highlights\n\n- **Complete MSBuild Integration**: Eliminated CLI tool dependency, moved all build processes to MSBuild with deep Visual Studio integration\n- **Modernized Architecture**: Restructured process lifecycle with .NET launching first and running Electron as child process for better control and reliability\n- **Cross-Platform Development**: Build and debug Linux applications directly from Windows Visual Studio via WSL integration\n- **Flexible Electron Versioning**: Removed version lock-in, users can now select any Electron version with build-time validation\n- **Enhanced Debugging Experience**: ASP.NET-first debugging with Hot Reload support and improved process termination handling\n- **Console App Support**: No longer requires ASP.NET - now works with simple console applications for file system or remote server HTML/JS\n\n### Build System & Project Structure\n\n- Eliminated electron.manifest.json configuration file, replaced with MSBuild project properties\n- Introduced new package structure: ElectronNET.Core (main package), ElectronNET.Core.Api (API definitions), ElectronNET.Core.AspNet (ASP.NET integration)\n- Added Runtime Identifier (RID) selection as part of project configuration\n- Restructured build folder layout to use standard .NET format (bin\\net8.0\\win-x64) instead of bin\\Desktop\n- Implemented incremental build support for Electron assets to improve build performance\n- Added custom MSBuild tasks for Electron-specific build operations\n\n### Development Experience\n\n- Implemented unpackaged run-mode for development using regular .NET builds with unpackaged Electron configuration\n- Added support for building Linux packages on Windows via WSL integration\n- Enabled running and debugging Linux application outputs on Windows through WSL\n- Integrated TypeScript compilation with ASP.NET tooling for consistent builds\n- Added process orchestration supporting 8 different launch scenarios (packaged/unpackaged × console/ASP.NET × dotnet-first/electron-first)\n\n### Debugging & Runtime\n\n- Dramatically improved debugging experience with ASP.NET-first launch mode\n- Added Hot Reload support for ASP.NET code during development\n- Implemented proper process termination handling for all exit scenarios\n- Minimized startup times through optimized build and launch procedures\n\n### Technical Improvements\n\n- Enhanced splash screen handling with automatic path resolution\n- Improved ElectronHostHook integration as proper npm package dependency\n- Updated to latest TypeScript version with ESLint configuration\n- Added support for custom main.js files in projects\n- Implemented version management through common.props file\n- Added build-time Electron version compatibility validation\n\n### Package & Distribution\n\n- Integrated MSBuild publishing mechanisms for creating Electron packages\n- Added folder publishing support with improved parameter handling\n- Implemented automated package.json generation from MSBuild properties\n- Added GitHub release automation with proper versioning\n- Reduced package sizes by eliminating unnecessary TypeScript dependencies\n\n### Migration & Compatibility\n\n- Maintained backward compatibility for existing ElectronHostHook implementations\n- Removed ASP.NET requirement: Now works with simple console applications for file system or remote server HTML/JS scenarios\n- Added support for both console and ASP.NET Core application types\n- Preserved all existing Electron API functionality while modernizing architecture\n- Added migration path for existing projects through updated package structure\n\nThis represents a comprehensive modernization of Electron.NET, addressing the major pain points around debugging, build complexity, and platform limitations while maintaining full API compatibility.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017-2025 Gregor Biswanger, Robert Mühsig, Florian Rappl\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "NuGet.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <config>\n    <add key=\"repositoryPath\" value=\"artifacts\" />\n  </config>\n  <packageSources>\n    <clear />\n    <add key=\"LocalDev\" value=\"artifacts\" />\n    <add key=\"nuget.org\" value=\"https://api.nuget.org/v3/index.json\" protocolVersion=\"3\" />\n  </packageSources>\n</configuration>"
  },
  {
    "path": "README.md",
    "content": "[![Electron.NET Logo](https://github.com/ElectronNET/Electron.NET/raw/main/assets/images/electron.net-logo.png)](https://github.com/ElectronNET/Electron.NET)\n\n[![donate](https://img.shields.io/badge/Donate-Donorbox-green.svg)](https://donorbox.org/electron-net) [![Gitter](https://badges.gitter.im/ElectronNET/community.svg)](https://gitter.im/ElectronNET/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build status](https://github.com/ElectronNET/Electron.NET/actions/workflows/ci.yml/badge.svg)](https://github.com/ElectronNET/Electron.NET/actions/workflows/ci.yml)\n\n# Electron.NET Core is here!\n\n## A Complete Transformation\n\n`ElectronNET.Core` represents a fundamental modernization of Electron.NET, addressing years of accumulated pain points while preserving full API compatibility. This isn't just an update — it's a complete rethinking of how .NET developers build and debug cross-platform desktop applications with Electron.\n\nRead more: [**What's New in `ElectronNET.Core`**](https://github.com/ElectronNET/Electron.NET/wiki/What's-New)\n\nBuild cross platform desktop applications with .NET 6/8/10 - from console apps to ASP.NET Core (Razor Pages, MVC) to Blazor.\n\n## Wait - how does that work exactly?\n\nWell... there are lots of different approaches how to get a X-plat desktop app running. Electron.NET provides a range of ways to build .NET-based solutions using Electron at the side of presentation.\n\nWhile the classic Electron.NET setup (using an ASP.NET host run by the Electron side) is still the primary way, there's more flexibility now. Both .NET and Electron are now able to launch the other for better lifetime management, and when you don't need a local web server (like when running content from files or remote servers), you can drop the ASP.NET stack altogether and go with a lightweight console app instead.\n\n## 📦 NuGet\n\n* ElectronNET.Core: [![NuGet](https://img.shields.io/nuget/v/ElectronNET.Core.svg?style=flat-square)](https://www.nuget.org/packages/ElectronNET.Core.API/)\n* ElectronNET.Core.API: [![NuGet](https://img.shields.io/nuget/v/ElectronNET.Core.API.svg?style=flat-square)](https://www.nuget.org/packages/ElectronNET.Core.API/)\n* ElectronNET.Core.AspNet: [![NuGet](https://img.shields.io/nuget/v/ElectronNET.Core.AspNet.svg?style=flat-square)](https://www.nuget.org/packages/ElectronNET.Core.AspNet/)\n\n## 🛠 Requirements to Run\n\nYou should have installed:\n\n* .NET 6/8 or later.\n* The minimum base OS is the same as [.NET 6](https://github.com/dotnet/core/blob/main/release-notes/6.0/supported-os.md) / [.NET 8](https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md).\n* Node.JS using at least [Version 22.x](https://nodejs.org).\n\n## 👩‍🏫 Usage with ASP.NET\n\n- Create a new ASP.NET Core project\n- Install the following two NuGet packages:\n\n```ps1\ndotnet add package ElectronNET.Core\n\ndotnet add package ElectronNET.Core.AspNet\n```\n\n### Classic ASP.NET Core\n\n#### Enable Electron.NET on Startup\n\nTo do so, use the `UseElectron` extension method on a `WebApplicationBuilder`, an `IWebHostBuilder` or any descendants.\n\n> [!NOTE]  \n> New in Electron.NET Core is that you provide a callback method as an argument to `UseElectron()`, which ensures that you get to know the right moment to set up your application UI.\n\n#### Program.cs\n\n```csharp\t\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\npublic static void Main(string[] args)\n{\n    WebHost.CreateDefaultBuilder(args)\n        .UseElectron(args, ElectronAppReady)\n        .UseStartup<Startup>()\n        .Build()\n        .Run();\n}\n\npublic static async Task ElectronAppReady()\n{\n    var browserWindow = await Electron.WindowManager.CreateWindowAsync(\n        new BrowserWindowOptions { Show = false });\n\n    browserWindow.OnReadyToShow += () => browserWindow.Show();\n}\n```\n\n### Minimal API Example\n\nFor a minimal API you can use:\n\n```csharp\nusing ElectronNET;\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddRazorPages();\nbuilder.Services.AddElectron(); // <- might be useful to set up DI\n\nbuilder.UseElectron(args, async () =>\n{\n    var browserWindow = await Electron.WindowManager.CreateWindowAsync(\n        new BrowserWindowOptions { Show = false, AutoHideMenuBar = true });\n\n    browserWindow.OnReadyToShow += () => browserWindow.Show();\n});\n\nvar app = builder.Build();\n\n// Configure the HTTP request pipeline.\nif (!app.Environment.IsDevelopment())\n{\n    app.UseExceptionHandler(\"/Error\");\n}\n\napp.UseStaticFiles();\napp.UseRouting();\napp.UseAuthorization();\napp.MapRazorPages();\napp.Run();\n```\n\n### Blazor\n\nFor a project with Blazor you can use:\n\n```cs\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services\n    .AddRazorComponents()\n    .AddInteractiveWebAssemblyComponents();\n\nbuilder.Services.AddElectron(); // <-- might be useful to set up DI\n\nbuilder.UseElectron(args, async () =>\n{\n    var options = new BrowserWindowOptions {\n        Show = false,\n        IsRunningBlazor = true, // <-- crucial\n    };\n    if (OperatingSystem.IsWindows() || OperatingSystem.IsLinux())\n        options.AutoHideMenuBar = true;\n    var browserWindow = await Electron.WindowManager.CreateWindowAsync(options);\n    browserWindow.OnReadyToShow += () => browserWindow.Show();\n});\n\nvar app = builder.Build();\n\n// Configure the HTTP request pipeline.\nif (app.Environment.IsDevelopment())\n{\n    app.UseWebAssemblyDebugging();\n}\nelse\n{\n    app.UseExceptionHandler(\"/Error\", createScopeForErrors: true);\n}\n\napp.UseStaticFiles();\napp.UseAntiforgery();\n\napp.MapRazorComponents<BlazorApp.Components.App>()\n    .AddInteractiveWebAssemblyRenderMode();\n\napp.Run();\n```\n\nThe `IsRunningBlazor` option makes sure to set up the renderer in a way that Blazor can just run without any interference. This includes things such as HMR for development.\n\n## 🚀 Starting and Debugging the Application\n\nJust press `F5` in Visual Studio or use dotnet for debugging.\n\n## 📔 Usage of the Electron API\n\nComplete documentation is available on the Wiki.\n\nIn this YouTube video, we show you how you can create a new project, use the Electron.NET API, debug a application and build an executable desktop app for Windows: [Electron.NET - Getting Started](https://www.youtube.com/watch?v=nuM6AojRFHk)  \n  \n  > [!NOTE]  \n  > The video hasn't been updated for the changes in ElectronNET.Core, so it is partially outdated.\n\n## 👨‍💻 Authors\n\n* **[Gregor Biswanger](https://github.com/GregorBiswanger)** - (Microsoft MVP, Intel Black Belt and Intel Software Innovator) is a freelance lecturer, consultant, trainer, author and speaker. He is a consultant for large and medium-sized companies, organizations and agencies for software architecture, web- and cross-platform development. You can find Gregor often on the road attending or speaking at international conferences. - [Cross-Platform-Blog](http://www.cross-platform-blog.com) - Twitter [@BFreakout](https://www.twitter.com/BFreakout)  \n* **[Dr. Florian Rappl](https://github.com/FlorianRappl)** - Software Developer - from Munich, Germany. Microsoft MVP & Web Geek. - [The Art of Micro Frontends](https://microfrontends.art) - [Homepage](https://florian-rappl.de) - Twitter [@florianrappl](https://twitter.com/florianrappl)\n* **[softworkz](https://github.com/softworkz)** - Full Range Developer - likes to start where others gave up. MS MVP alumni and Munich citizen as well.\n* **[Robert Muehsig](https://github.com/robertmuehsig)** - Software Developer - from Dresden, Germany, now living & working in Switzerland. Microsoft MVP & Web Geek. - [codeinside Blog](https://blog.codeinside.eu) - Twitter [@robert0muehsig](https://twitter.com/robert0muehsig)  \n  \nSee also the list of [contributors](https://github.com/ElectronNET/Electron.NET/graphs/contributors) who participated in this project.\n  \n## 🙋‍♀️🙋‍♂ Contributing\n\nFeel free to submit a pull request if you find any bugs (to see a list of active issues, visit the [Issues section](https://github.com/ElectronNET/Electron.NET/issues).\nPlease make sure all commits are properly documented.\n\n## 🙏 Donate\n\nWe do this open source work in our free time. If you'd like us to invest more time on it, please [donate](https://donorbox.org/electron-net). Donation can be used to increase some issue priority. Thank you!\n\n[![donate](https://img.shields.io/badge/Donate-Donorbox-green.svg)](https://donorbox.org/electron-net)\n\nAlternatively, consider using a GitHub sponsorship for the core maintainers:\n\n- [Gregor Biswanger](https://github.com/sponsors/GregorBiswanger)\n- [Florian Rappl](https://github.com/sponsors/FlorianRappl)\n\nAny support appreciated! 🍻\n\n## 🎉 License\n\nMIT-licensed. See [LICENSE](https://github.com/ElectronNET/Electron.NET/blob/main/LICENSE) for details.\n\n**Enjoy!**\n\n"
  },
  {
    "path": "artifacts/.gitkeep",
    "content": ""
  },
  {
    "path": "build.cmd",
    "content": ":; set -eo pipefail\n:; SCRIPT_DIR=$(cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd)\n:; ${SCRIPT_DIR}/build.sh \"$@\"\n:; exit $?\n\n@ECHO OFF\npowershell -ExecutionPolicy ByPass -NoProfile -File \"%~dp0build.ps1\" %*\n"
  },
  {
    "path": "build.ps1",
    "content": "[CmdletBinding()]\nParam(\n    [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]\n    [string[]]$BuildArguments\n)\n\nWrite-Output \"PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)\"\n\nSet-StrictMode -Version 2.0; $ErrorActionPreference = \"Stop\"; $ConfirmPreference = \"None\"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }\n$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent\n\n###########################################################################\n# CONFIGURATION\n###########################################################################\n\n$BuildProjectFile = \"$PSScriptRoot\\nuke\\_build.csproj\"\n$TempDirectory = \"$PSScriptRoot\\\\.nuke\\temp\"\n\n$DotNetGlobalFile = \"$PSScriptRoot\\\\global.json\"\n$DotNetInstallUrl = \"https://dot.net/v1/dotnet-install.ps1\"\n$DotNetChannel = \"Current\"\n\n$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1\n$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1\n$env:DOTNET_MULTILEVEL_LOOKUP = 0\n\n###########################################################################\n# EXECUTION\n###########################################################################\n\nfunction ExecSafe([scriptblock] $cmd) {\n    & $cmd\n    if ($LASTEXITCODE) { exit $LASTEXITCODE }\n}\n\n# If dotnet CLI is installed globally and it matches requested version, use for execution\nif ($null -ne (Get-Command \"dotnet\" -ErrorAction SilentlyContinue) -and `\n     $(dotnet --version) -and $LASTEXITCODE -eq 0) {\n    $env:DOTNET_EXE = (Get-Command \"dotnet\").Path\n}\nelse {\n    # Download install script\n    $DotNetInstallFile = \"$TempDirectory\\dotnet-install.ps1\"\n    New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null\n    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n    (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)\n\n    # If global.json exists, load expected version\n    if (Test-Path $DotNetGlobalFile) {\n        $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)\n        if ($DotNetGlobal.PSObject.Properties[\"sdk\"] -and $DotNetGlobal.sdk.PSObject.Properties[\"version\"]) {\n            $DotNetVersion = $DotNetGlobal.sdk.version\n        }\n    }\n\n    # Install by channel or version\n    $DotNetDirectory = \"$TempDirectory\\dotnet-win\"\n    if (!(Test-Path variable:DotNetVersion)) {\n        ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }\n    } else {\n        ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }\n    }\n    $env:DOTNET_EXE = \"$DotNetDirectory\\dotnet.exe\"\n}\n\nWrite-Output \"Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)\"\n\nExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }\nExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }\n"
  },
  {
    "path": "build.sh",
    "content": "#!/usr/bin/env bash\n\nbash --version 2>&1 | head -n 1\n\nset -eo pipefail\nSCRIPT_DIR=$(cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd)\n\n###########################################################################\n# CONFIGURATION\n###########################################################################\n\nBUILD_PROJECT_FILE=\"$SCRIPT_DIR/nuke/_build.csproj\"\nTEMP_DIRECTORY=\"$SCRIPT_DIR//.nuke/temp\"\n\nDOTNET_GLOBAL_FILE=\"$SCRIPT_DIR//global.json\"\nDOTNET_INSTALL_URL=\"https://dot.net/v1/dotnet-install.sh\"\nDOTNET_CHANNEL=\"Current\"\n\nexport DOTNET_CLI_TELEMETRY_OPTOUT=1\nexport DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1\nexport DOTNET_MULTILEVEL_LOOKUP=0\n\n###########################################################################\n# EXECUTION\n###########################################################################\n\nfunction FirstJsonValue {\n    perl -nle 'print $1 if m{\"'\"$1\"'\": \"([^\"]+)\",?}' <<< \"${@:2}\"\n}\n\n# If dotnet CLI is installed globally and it matches requested version, use for execution\nif [ -x \"$(command -v dotnet)\" ] && dotnet --version &>/dev/null; then\n    export DOTNET_EXE=\"$(command -v dotnet)\"\nelse\n    # Download install script\n    DOTNET_INSTALL_FILE=\"$TEMP_DIRECTORY/dotnet-install.sh\"\n    mkdir -p \"$TEMP_DIRECTORY\"\n    curl -Lsfo \"$DOTNET_INSTALL_FILE\" \"$DOTNET_INSTALL_URL\"\n    chmod +x \"$DOTNET_INSTALL_FILE\"\n\n    # If global.json exists, load expected version\n    if [[ -f \"$DOTNET_GLOBAL_FILE\" ]]; then\n        DOTNET_VERSION=$(FirstJsonValue \"version\" \"$(cat \"$DOTNET_GLOBAL_FILE\")\")\n        if [[ \"$DOTNET_VERSION\" == \"\"  ]]; then\n            unset DOTNET_VERSION\n        fi\n    fi\n\n    # Install by channel or version\n    DOTNET_DIRECTORY=\"$TEMP_DIRECTORY/dotnet-unix\"\n    if [[ -z ${DOTNET_VERSION+x} ]]; then\n        \"$DOTNET_INSTALL_FILE\" --install-dir \"$DOTNET_DIRECTORY\" --channel \"$DOTNET_CHANNEL\" --no-path\n    else\n        \"$DOTNET_INSTALL_FILE\" --install-dir \"$DOTNET_DIRECTORY\" --version \"$DOTNET_VERSION\" --no-path\n    fi\n    export DOTNET_EXE=\"$DOTNET_DIRECTORY/dotnet\"\nfi\n\necho \"Microsoft (R) .NET SDK version $(\"$DOTNET_EXE\" --version)\"\n\n\"$DOTNET_EXE\" build \"$BUILD_PROJECT_FILE\" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet\n\"$DOTNET_EXE\" run --project \"$BUILD_PROJECT_FILE\" --no-build -- \"$@\"\n"
  },
  {
    "path": "docs/.docproj/DocProj.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <TargetPlatformVersion>8.1</TargetPlatformVersion>\n    <IsCodeSharingProject>true</IsCodeSharingProject>\n    <DefineCommonItemSchemas>true</DefineCommonItemSchemas>\n  </PropertyGroup>\n  \n  <PropertyGroup>\n    <MdIncludes>**/*.md;**/*.markdown</MdIncludes>\n    <ImageIncludes>**/*.png;**/*.bmp;**/*.jpg;**/*.gif;**/*.mp4</ImageIncludes>\n    <WebIncludes>**/*.css;**/*.js;**/*.json</WebIncludes>\n  </PropertyGroup>\n  \n  <ItemGroup>\n    <Compile Remove=\"**/*\" />\n    <Content Remove=\"**/*\" />\n  </ItemGroup>\n  \n  <ItemGroup>\n    <None Include=\"$(ImageIncludes)\" />\n    <None Include=\"$(WebIncludes)\" />\n    <None Include=\"$(MdIncludes)\" />\n  </ItemGroup>\n  \n</Project>\n"
  },
  {
    "path": "docs/.docproj/DocProj.targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>    \n    <ProjectCapability Include=\"SourceItemsFromImports;SharedImports;SharedAssetsProject\"/>\n    <ProjectCapability Include=\"HandlesOwnReload\"/>\n    <ProjectCapability Include=\"UserSourceItems\"/>    \n    <ProjectCapability Include=\"OpenProjectFile\"/>    \n    <ProjectCapability Include=\"UseFileGlobs\"/>    \n    <ProjectCapability Include=\"SingleFileGenerators\"/>    \n  </ItemGroup>\n\n  <Target Name=\"Compile\">\n  </Target>\n\n  <Target Name=\"Build\">\n  </Target>\n\n  <Target Name=\"Clean\">\n  </Target>\n\n  <Target Name=\"_CheckForInvalidConfigurationAndPlatform\">\n  </Target>\n</Project>\n"
  },
  {
    "path": "docs/API/App.md",
    "content": "# Electron.App\n\nControl your application's event lifecycle.\n\n## Overview\n\nThe `Electron.App` API provides comprehensive control over your application's lifecycle, including startup, shutdown, window management, and system integration. It handles application-level events and provides methods for managing the overall application state.\n\n## Properties\n\n#### 📋 `CommandLine`\nA `CommandLine` object that allows you to read and manipulate the command line arguments that Chromium uses.\n\n#### 📋 `IsReady`\nApplication host fully started.\n\n#### 📋 `Name`\nA string property that indicates the current application's name, which is the name in the application's package.json file.\n\nUsually the name field of package.json is a short lowercase name, according to the npm modules spec. You should usually also specify a productName field, which is your application's full capitalized name, and which will be preferred over name by Electron.\n\n#### 📋 `NameAsync`\nA `Task<string>` property that indicates the current application's name, which is the name in the application's package.json file.\n\nUsually the name field of package.json is a short lowercase name, according to the npm modules spec. You should usually also specify a productName field, which is your application's full capitalized name, and which will be preferred over name by Electron.\n\n#### 📋 `UserAgentFallback`\nA string which is the user agent string Electron will use as a global fallback.\n\nThis is the user agent that will be used when no user agent is set at the webContents or session level. It is useful for ensuring that your entire app has the same user agent. Set to a custom value as early as possible in your app's initialization to ensure that your overridden value is used.\n\n#### 📋 `UserAgentFallbackAsync`\nA `Task<string>` which is the user agent string Electron will use as a global fallback.\n\nThis is the user agent that will be used when no user agent is set at the webContents or session level. It is useful for ensuring that your entire app has the same user agent. Set to a custom value as early as possible in your app's initialization to ensure that your overridden value is used.\n\n## Methods\n\n#### 🧊 `void AddRecentDocument(string path)`\nAdds path to the recent documents list. This list is managed by the OS. On Windows you can visit the list from the task bar, and on macOS you can visit it from dock menu.\n\n#### 🧊 `void ClearRecentDocuments()`\nClears the recent documents list.\n\n#### 🧊 `void Exit(int exitCode = 0)`\nAll windows will be closed immediately without asking user and the BeforeQuit and WillQuit events will not be emitted.\n\n**Parameters:**\n- `exitCode` - Exits immediately with exitCode. exitCode defaults to 0.\n\n#### 🧊 `void Focus()`\nOn Linux, focuses on the first visible window. On macOS, makes the application the active app. On Windows, focuses on the application's first window.\n\n#### 🧊 `void Focus(FocusOptions focusOptions)`\nOn Linux, focuses on the first visible window. On macOS, makes the application the active app. On Windows, focuses on the application's first window.\n\nYou should seek to use the `FocusOptions.Steal` option as sparingly as possible.\n\n**Parameters:**\n- `focusOptions` - Focus options\n\n#### 🧊 `Task<ProcessMetric[]> GetAppMetricsAsync(CancellationToken cancellationToken = default)`\nMemory and cpu usage statistics of all the processes associated with the app.\n\n**Returns:**\n\nArray of ProcessMetric objects that correspond to memory and cpu usage statistics of all the processes associated with the app.\n\n#### 🧊 `Task<string> GetAppPathAsync(CancellationToken cancellationToken = default)`\nThe current application directory.\n\n**Returns:**\n\nThe current application directory.\n\n#### 🧊 `Task<int> GetBadgeCountAsync(CancellationToken cancellationToken = default)`\nThe current value displayed in the counter badge.\n\n**Returns:**\n\nThe current value displayed in the counter badge.\n\n#### 🧊 `Task<string> GetCurrentActivityTypeAsync(CancellationToken cancellationToken = default)`\nThe type of the currently running activity.\n\n**Returns:**\n\nThe type of the currently running activity.\n\n#### 🧊 `Task<GPUFeatureStatus> GetGpuFeatureStatusAsync(CancellationToken cancellationToken = default)`\nThe Graphics Feature Status from chrome://gpu/.\n\nNote: This information is only usable after the gpu-info-update event is emitted.\n\n**Returns:**\n\nThe Graphics Feature Status from chrome://gpu/.\n\n#### 🧊 `Task<JumpListSettings> GetJumpListSettingsAsync(CancellationToken cancellationToken = default)`\nJump List settings for the application.\n\n**Returns:**\n\nJump List settings.\n\n#### 🧊 `Task<string> GetLocaleAsync(CancellationToken cancellationToken = default)`\nThe current application locale. Possible return values are documented [here](https://www.electronjs.org/docs/api/locales).\n\nNote: When distributing your packaged app, you have to also ship the locales folder.\n\nNote: On Windows, you have to call it after the Ready events gets emitted.\n\n**Returns:**\n\nThe current application locale.\n\n#### 🧊 `Task<LoginItemSettings> GetLoginItemSettingsAsync(CancellationToken cancellationToken = default)`\nIf you provided path and args options to SetLoginItemSettings then you need to pass the same arguments here for LoginItemSettings.OpenAtLogin to be set correctly.\n\n**Returns:**\n\nLogin item settings.\n\n#### 🧊 `Task<string> GetPathAsync(PathName pathName, CancellationToken cancellationToken = default)`\nThe path to a special directory. If GetPathAsync is called without called SetAppLogsPath being called first, a default directory will be created equivalent to calling SetAppLogsPath without a path parameter.\n\n**Parameters:**\n- `pathName` - Special directory.\n\n**Returns:**\n\nA path to a special directory or file associated with name.\n\n#### 🧊 `Task<string> GetVersionAsync(CancellationToken cancellationToken = default)`\nThe version of the loaded application. If no version is found in the application's package.json file, the version of the current bundle or executable is returned.\n\n**Returns:**\n\nThe version of the loaded application.\n\n#### 🧊 `Task<bool> HasSingleInstanceLockAsync(CancellationToken cancellationToken = default)`\nThis method returns whether or not this instance of your app is currently holding the single instance lock. You can request the lock with RequestSingleInstanceLockAsync and release with ReleaseSingleInstanceLock.\n\n**Returns:**\n\nWhether this instance of your app is currently holding the single instance lock.\n\n#### 🧊 `void Hide()`\nHides all application windows without minimizing them.\n\n#### 🧊 `Task<int> ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default)`\nImports the certificate in pkcs12 format into the platform certificate store. callback is called with the result of import operation, a value of 0 indicates success while any other value indicates failure according to chromium net_error_list.\n\n**Parameters:**\n- `options` - Import certificate options\n- `cancellationToken` - The cancellation token\n\n**Returns:**\n\nResult of import. Value of 0 indicates success.\n\n#### 🧊 `void InvalidateCurrentActivity()`\nInvalidates the current Handoff user activity.\n\n#### 🧊 `Task<bool> IsAccessibilitySupportEnabledAsync(CancellationToken cancellationToken = default)`\ntrue if Chrome's accessibility support is enabled, false otherwise. This API will return true if the use of assistive technologies, such as screen readers, has been detected. See Chromium's accessibility docs for more details.\n\n**Returns:**\n\ntrue if Chrome's accessibility support is enabled, false otherwise.\n\n#### 🧊 `Task<bool> IsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default)`\nThis method checks if the current executable is the default handler for a protocol (aka URI scheme).\n\nNote: On macOS, you can use this method to check if the app has been registered as the default protocol handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist on the macOS machine. Please refer to Apple's documentation for details.\n\nThe API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally.\n\n**Parameters:**\n- `protocol` - The name of your protocol, without ://\n- `cancellationToken` - The cancellation token\n\n**Returns:**\n\nWhether the current executable is the default handler for a protocol (aka URI scheme).\n\n#### 🧊 `Task<bool> IsUnityRunningAsync(CancellationToken cancellationToken = default)`\nWhether the current desktop environment is Unity launcher.\n\n**Returns:**\n\nWhether the current desktop environment is Unity launcher.\n\n#### 🧊 `void Quit()`\nTry to close all windows. The BeforeQuit event will be emitted first. If all windows are successfully closed, the WillQuit event will be emitted and by default the application will terminate. This method guarantees that all beforeunload and unload event handlers are correctly executed. It is possible that a window cancels the quitting by returning false in the beforeunload event handler.\n\n#### 🧊 `void ReleaseSingleInstanceLock()`\nReleases all locks that were created by makeSingleInstance. This will allow multiple instances of the application to once again run side by side.\n\n#### 🧊 `void Relaunch()`\nRelaunches the app when current instance exits. By default the new instance will use the same working directory and command line arguments with current instance.\n\nNote that this method does not quit the app when executed, you have to call Quit or Exit after calling Relaunch() to make the app restart.\n\nWhen Relaunch() is called for multiple times, multiple instances will be started after current instance exited.\n\n#### 🧊 `void Relaunch(RelaunchOptions relaunchOptions)`\nRelaunches the app when current instance exits. By default the new instance will use the same working directory and command line arguments with current instance. When RelaunchOptions.Args is specified, the RelaunchOptions.Args will be passed as command line arguments instead. When RelaunchOptions.ExecPath is specified, the RelaunchOptions.ExecPath will be executed for relaunch instead of current app.\n\nNote that this method does not quit the app when executed, you have to call Quit or Exit after calling Relaunch() to make the app restart.\n\nWhen Relaunch() is called for multiple times, multiple instances will be started after current instance exited.\n\n**Parameters:**\n- `relaunchOptions` - Options for the relaunch\n\n#### 🧊 `Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default)`\nThis method checks if the current executable as the default handler for a protocol (aka URI scheme). If so, it will remove the app as the default handler.\n\n**Parameters:**\n- `protocol` - The name of your protocol, without ://\n- `cancellationToken` - The cancellation token\n\n**Returns:**\n\nWhether the call succeeded.\n\n#### 🧊 `Task<bool> RequestSingleInstanceLockAsync(Action<string[], string> newInstanceOpened, CancellationToken cancellationToken = default)`\nThe return value of this method indicates whether or not this instance of your application successfully obtained the lock. If it failed to obtain the lock, you can assume that another instance of your application is already running with the lock and exit immediately.\n\nI.e.This method returns true if your process is the primary instance of your application and your app should continue loading. It returns false if your process should immediately quit as it has sent its parameters to another instance that has already acquired the lock.\n\nOn macOS, the system enforces single instance automatically when users try to open a second instance of your app in Finder, and the open-file and open-url events will be emitted for that.However when users start your app in command line, the system's single instance mechanism will be bypassed, and you have to use this method to ensure single instance.\n\n**Parameters:**\n- `newInstanceOpened` - Lambda with an array of the second instance's command line arguments. The second parameter is the working directory path.\n- `cancellationToken` - The cancellation token\n\n**Returns:**\n\nThis method returns false if your process is the primary instance of the application and your app should continue loading. And returns true if your process has sent its parameters to another instance, and you should immediately quit.\n\n#### 🧊 `void ResignCurrentActivity()`\nMarks the current Handoff user activity as inactive without invalidating it.\n\n#### 🧊 `void SetAccessibilitySupportEnabled(bool enabled)`\nManually enables Chrome's accessibility support, allowing to expose accessibility switch to users in application settings. See Chromium's accessibility docs for more details. Disabled (false) by default.\n\nThis API must be called after the Ready event is emitted.\n\nNote: Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default.\n\n**Parameters:**\n- `enabled` - Enable or disable accessibility tree rendering\n\n#### 🧊 `void SetAppLogsPath(string path)`\nSets or creates a directory your app's logs which can then be manipulated with GetPathAsync or SetPath.\n\nCalling SetAppLogsPath without a path parameter will result in this directory being set to ~/Library/Logs/YourAppName on macOS, and inside the userData directory on Linux and Windows.\n\n**Parameters:**\n- `path` - A custom path for your logs. Must be absolute\n\n#### 🧊 `void SetAppUserModelId(string id)`\nChanges the Application User Model ID to id.\n\n**Parameters:**\n- `id` - Model Id\n\n#### 🧊 `Task<bool> SetAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default)`\nSets the current executable as the default handler for a protocol (aka URI scheme). It allows you to integrate your app deeper into the operating system. Once registered, all links with your-protocol:// will be opened with the current executable. The whole link, including protocol, will be passed to your application as a parameter.\n\nNote: On macOS, you can only register protocols that have been added to your app's info.plist, which cannot be modified at runtime. However, you can change the file during build time via Electron Forge, Electron Packager, or by editing info.plist with a text editor. Please refer to Apple's documentation for details.\n\nNote: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but the registry key it sets won't be accessible by other applications. In order to register your Windows Store application as a default protocol handler you must declare the protocol in your manifest.\n\nThe API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally.\n\n**Parameters:**\n- `protocol` - The name of your protocol, without ://. For example, if you want your app to handle electron:// links, call this method with electron as the parameter.\n- `cancellationToken` - The cancellation token\n\n**Returns:**\n\nWhether the call succeeded.\n\n#### 🧊 `Task<bool> SetBadgeCountAsync(int count, CancellationToken cancellationToken = default)`\nSets the counter badge for current app. Setting the count to 0 will hide the badge. On macOS it shows on the dock icon. On Linux it only works for Unity launcher.\n\nNote: Unity launcher requires the existence of a .desktop file to work, for more information please read Desktop Environment Integration.\n\n**Parameters:**\n- `count` - Counter badge\n- `cancellationToken` - The cancellation token\n\n**Returns:**\n\nWhether the call succeeded.\n\n#### 🧊 `void SetJumpList(JumpListCategory[] categories)`\nSets or removes a custom Jump List for the application. If categories is null the previously set custom Jump List (if any) will be replaced by the standard Jump List for the app (managed by Windows).\n\nNote: If a JumpListCategory object has neither the Type nor the Name property set then its Type is assumed to be tasks. If the Name property is set but the Type property is omitted then the Type is assumed to be custom.\n\nNote: Users can remove items from custom categories, and Windows will not allow a removed item to be added back into a custom category until after the next successful call to SetJumpList. Any attempt to re-add a removed item to a custom category earlier than that will result in the entire custom category being omitted from the Jump List. The list of removed items can be obtained using GetJumpListSettingsAsync.\n\n**Parameters:**\n- `categories` - Array of JumpListCategory objects\n\n#### 🧊 `void SetLoginItemSettings(LoginSettings loginSettings)`\nSet the app's login item settings.\n\nTo work with Electron's autoUpdater on Windows, which uses Squirrel, you'll want to set the launch path to Update.exe, and pass arguments that specify your application name.\n\n**Parameters:**\n- `loginSettings` - Login settings\n\n#### 🧊 `void SetPath(PathName name, string path)`\nOverrides the path to a special directory or file associated with name. If the path specifies a directory that does not exist, an Error is thrown. In that case, the directory should be created with fs.mkdirSync or similar.\n\nYou can only override paths of a name defined in GetPathAsync.\n\nBy default, web pages' cookies and caches will be stored under the PathName.UserData directory. If you want to change this location, you have to override the PathName.UserData path before the Ready event of the App module is emitted.\n\n**Parameters:**\n- `name` - Special directory name\n- `path` - New path to a special directory\n\n#### 🧊 `void SetUserActivity(string type, object userInfo)`\nCreates an NSUserActivity and sets it as the current activity. The activity is eligible for Handoff to another device afterward.\n\n**Parameters:**\n- `type` - Uniquely identifies the activity. Maps to NSUserActivity.activityType.\n- `userInfo` - App-specific state to store for use by another device\n\n#### 🧊 `Task<bool> SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default)`\nAdds tasks to the UserTask category of the JumpList on Windows.\n\nNote: If you'd like to customize the Jump List even more use SetJumpList instead.\n\n**Parameters:**\n- `userTasks` - Array of UserTask objects\n- `cancellationToken` - The cancellation token\n\n**Returns:**\n\nWhether the call succeeded.\n\n#### 🧊 `void Show()`\nShows application windows after they were hidden. Does not automatically focus them.\n\n#### 🧊 `void ShowAboutPanel()`\nShow the app's about panel options. These options can be overridden with SetAboutPanelOptions.\n\n## Events\n\n#### ⚡ `AccessibilitySupportChanged`\nEmitted when Chrome's accessibility support changes. This event fires when assistive technologies, such as screen readers, are enabled or disabled. See https://www.chromium.org/developers/design-documents/accessibility for more details.\n\n#### ⚡ `BrowserWindowBlur`\nEmitted when a BrowserWindow blurred.\n\n#### ⚡ `BrowserWindowCreated`\nEmitted when a new BrowserWindow is created.\n\n#### ⚡ `BrowserWindowFocus`\nEmitted when a BrowserWindow gets focused.\n\n#### ⚡ `OpenFile`\nEmitted when a macOS user wants to open a file with the application. The open-file event is usually emitted when the application is already open and the OS wants to reuse the application to open the file. open-file is also emitted when a file is dropped onto the dock and the application is not yet running.\n\nOn Windows, you have to parse the arguments using App.CommandLine to get the filepath.\n\n#### ⚡ `OpenUrl`\nEmitted when a macOS user wants to open a URL with the application. Your application's Info.plist file must define the URL scheme within the CFBundleURLTypes key, and set NSPrincipalClass to AtomApplication.\n\n#### ⚡ `Quitting`\nEmitted when the application is quitting.\n\nNote: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout.\n\n#### ⚡ `Ready`\nEmitted when the application has finished basic startup.\n\n#### ⚡ `WebContentsCreated`\nEmitted when a new WebContents is created.\n\n#### ⚡ `WillQuit`\nEmitted when all windows have been closed and the application will quit.\n\nSee the description of the WindowAllClosed event for the differences between the WillQuit and WindowAllClosed events.\n\nNote: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout.\n\n#### ⚡ `WindowAllClosed`\nEmitted when all windows have been closed.\n\nIf you do not subscribe to this event and all windows are closed, the default behavior is to quit the app; however, if you subscribe, you control whether the app quits or not.If the user pressed Cmd + Q, or the developer called Quit, Electron will first try to close all the windows and then emit the WillQuit event, and in this case the WindowAllClosed event would not be emitted.\n\n## Usage Examples\n\n### Application Lifecycle\n\n```csharp\n// Handle app startup\nElectron.App.Ready += () =>\n{\n    Console.WriteLine(\"App is ready!\");\n};\n\n// Handle window management\nElectron.App.WindowAllClosed += () =>\n{\n    if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n    {\n        Electron.App.Quit();\n    }\n};\n\n// Prevent quit\nElectron.App.BeforeQuit += async (args) =>\n{\n    var result = await Electron.Dialog.ShowMessageBoxAsync(\"Do you want to quit?\");\n    if (result.Response == 1) // Cancel\n    {\n        args.PreventDefault = true;\n    }\n};\n```\n\n### Protocol Handling\n\n```csharp\n// Register custom protocol\nvar success = await Electron.App.SetAsDefaultProtocolClientAsync(\"myapp\");\n\n// Check if registered\nvar isDefault = await Electron.App.IsDefaultProtocolClientAsync(\"myapp\");\n```\n\n### Jump List (Windows)\n\n```csharp\n// Set user tasks\nawait Electron.App.SetUserTasksAsync(new[]\n{\n    new UserTask\n    {\n        Program = \"myapp.exe\",\n        Arguments = \"--new-document\",\n        Title = \"New Document\",\n        Description = \"Create a new document\"\n    }\n});\n```\n\n### Application Information\n\n```csharp\n// Get app information\nvar appPath = await Electron.App.GetAppPathAsync();\nvar version = await Electron.App.GetVersionAsync();\nvar locale = await Electron.App.GetLocaleAsync();\n\n// Set app name\nawait Electron.App.NameAsync; // Get current name\nElectron.App.Name = \"My Custom App Name\";\n```\n\n### Badge Count (macOS/Linux)\n\n```csharp\n// Set badge count\nawait Electron.App.SetBadgeCountAsync(5);\n\n// Get current badge count\nvar count = await Electron.App.GetBadgeCountAsync();\n```\n\n## Related APIs\n\n- [Electron.WindowManager](WindowManager.md) - Window creation and management\n- [Electron.Dialog](Dialog.md) - User interaction dialogs\n- [Electron.Menu](Menu.md) - Application menus\n\n## Additional Resources\n\n- [Electron App Documentation](https://electronjs.org/docs/api/app) - Official Electron app API\n- [Startup Methods](../Using/Startup-Methods.md) - Different application startup modes\n"
  },
  {
    "path": "docs/API/AutoUpdater.md",
    "content": "# Electron.AutoUpdater\n\nHandle application updates and installation processes.\n\n## Overview\n\nThe `Electron.AutoUpdater` API provides comprehensive functionality for handling application updates, including checking for updates, downloading, and installation. It supports multiple update providers and platforms with automatic update capabilities.\n\n## Properties\n\n#### 📋 `bool AllowDowngrade`\nWhether to allow version downgrade. Default is false.\n\n#### 📋 `bool AllowPrerelease`\nGitHub provider only. Whether to allow update to pre-release versions. Defaults to true if application version contains prerelease components.\n\n#### 📋 `bool AutoDownload`\nWhether to automatically download an update when it is found. Default is true.\n\n#### 📋 `bool AutoInstallOnAppQuit`\nWhether to automatically install a downloaded update on app quit. Applicable only on Windows and Linux.\n\n#### 📋 `string Channel`\nGet the update channel. Not applicable for GitHub. Doesn't return channel from the update configuration, only if was previously set.\n\n#### 📋 `Task<string> ChannelAsync`\nGet the update channel. Not applicable for GitHub. Doesn't return channel from the update configuration, only if was previously set.\n\n#### 📋 `Task<SemVer> CurrentVersionAsync`\nGet the current application version.\n\n#### 📋 `bool FullChangelog`\nGitHub provider only. Get all release notes (from current version to latest), not just the latest. Default is false.\n\n#### 📋 `Dictionary<string, string> RequestHeaders`\nThe request headers.\n\n#### 📋 `Task<Dictionary<string, string>> RequestHeadersAsync`\nGet the current request headers.\n\n#### 📋 `string UpdateConfigPath`\nFor test only. Configuration path for updates.\n\n## Methods\n\n#### 🧊 `Task<UpdateCheckResult> CheckForUpdatesAndNotifyAsync()`\nAsks the server whether there is an update and notifies the user if an update is available.\n\n#### 🧊 `Task<UpdateCheckResult> CheckForUpdatesAsync()`\nAsks the server whether there is an update.\n\n#### 🧊 `Task<string> DownloadUpdateAsync()`\nStart downloading update manually. Use this method if AutoDownload option is set to false.\n\n**Returns:**\n\nPath to downloaded file.\n\n#### 🧊 `Task<string> GetFeedURLAsync()`\nGet the current feed URL.\n\n**Returns:**\n\nFeed URL.\n\n#### 🧊 `void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false)`\nRestarts the app and installs the update after it has been downloaded. Should only be called after update-downloaded has been emitted.\n\nNote: QuitAndInstall() will close all application windows first and only emit before-quit event on app after that. This is different from the normal quit event sequence.\n\n**Parameters:**\n- `isSilent` - Windows-only: Runs the installer in silent mode. Defaults to false\n- `isForceRunAfter` - Run the app after finish even on silent install. Not applicable for macOS\n\n## Events\n\n#### ⚡ `OnCheckingForUpdate`\nEmitted when checking if an update has started.\n\n#### ⚡ `OnDownloadProgress`\nEmitted on download progress.\n\n#### ⚡ `OnError`\nEmitted when there is an error while updating.\n\n#### ⚡ `OnUpdateAvailable`\nEmitted when there is an available update. The update is downloaded automatically if AutoDownload is true.\n\n#### ⚡ `OnUpdateDownloaded`\nEmitted on download complete.\n\n#### ⚡ `OnUpdateNotAvailable`\nEmitted when there is no available update.\n\n## Usage Examples\n\n### Basic Auto-Update Setup\n\n```csharp\n// Configure auto-updater\nElectron.AutoUpdater.AutoDownload = true;\nElectron.AutoUpdater.AutoInstallOnAppQuit = true;\n\n// Check for updates\nvar updateCheck = await Electron.AutoUpdater.CheckForUpdatesAsync();\nif (updateCheck.UpdateInfo != null)\n{\n    Console.WriteLine($\"Update available: {updateCheck.UpdateInfo.Version}\");\n}\n```\n\n### Manual Update Management\n\n```csharp\n// Disable auto-download for manual control\nElectron.AutoUpdater.AutoDownload = false;\n\n// Check for updates\nvar result = await Electron.AutoUpdater.CheckForUpdatesAsync();\nif (result.UpdateInfo != null)\n{\n    Console.WriteLine($\"Update found: {result.UpdateInfo.Version}\");\n\n    // Ask user confirmation\n    var confirmResult = await Electron.Dialog.ShowMessageBoxAsync(\n        \"Update Available\",\n        $\"Version {result.UpdateInfo.Version} is available. Download now?\");\n\n    if (confirmResult.Response == 1) // Yes\n    {\n        // Download update manually\n        var downloadPath = await Electron.AutoUpdater.DownloadUpdateAsync();\n        Console.WriteLine($\"Downloaded to: {downloadPath}\");\n\n        // Install update\n        Electron.AutoUpdater.QuitAndInstall();\n    }\n}\n```\n\n### Update Event Handling\n\n```csharp\n// Handle update events\nElectron.AutoUpdater.OnCheckingForUpdate += () =>\n{\n    Console.WriteLine(\"Checking for updates...\");\n};\n\nElectron.AutoUpdater.OnUpdateAvailable += (updateInfo) =>\n{\n    Console.WriteLine($\"Update available: {updateInfo.Version}\");\n};\n\nElectron.AutoUpdater.OnUpdateNotAvailable += (updateInfo) =>\n{\n    Console.WriteLine(\"No updates available\");\n};\n\nElectron.AutoUpdater.OnDownloadProgress += (progressInfo) =>\n{\n    Console.WriteLine($\"Download progress: {progressInfo.Percent}%\");\n};\n\nElectron.AutoUpdater.OnUpdateDownloaded += (updateInfo) =>\n{\n    Console.WriteLine($\"Update downloaded: {updateInfo.Version}\");\n\n    // Show notification to user\n    Electron.Notification.Show(new NotificationOptions\n    {\n        Title = \"Update Downloaded\",\n        Body = $\"Version {updateInfo.Version} is ready to install.\",\n        Actions = new[]\n        {\n            new NotificationAction { Text = \"Install Now\", Type = NotificationActionType.Button },\n            new NotificationAction { Text = \"Later\", Type = NotificationActionType.Button }\n        }\n    });\n};\n\nElectron.AutoUpdater.OnError += (error) =>\n{\n    Console.WriteLine($\"Update error: {error}\");\n    Electron.Dialog.ShowErrorBox(\"Update Error\", $\"Failed to update: {error}\");\n};\n```\n\n### GitHub Provider Configuration\n\n```csharp\n// Configure for GitHub releases\nElectron.AutoUpdater.AllowPrerelease = true; // Allow pre-release versions\nElectron.AutoUpdater.FullChangelog = true;  // Get full changelog\nElectron.AutoUpdater.AllowDowngrade = false; // Prevent downgrades\n\n// Set request headers if needed\nElectron.AutoUpdater.RequestHeaders = new Dictionary<string, string>\n{\n    [\"Authorization\"] = \"token your-github-token\",\n    [\"User-Agent\"] = \"MyApp-Updater\"\n};\n```\n\n### Update Installation\n\n```csharp\n// Install update immediately\nif (updateDownloaded)\n{\n    Electron.AutoUpdater.QuitAndInstall();\n}\n\n// Silent install (Windows only)\nElectron.AutoUpdater.QuitAndInstall(isSilent: true, isForceRunAfter: true);\n```\n\n### Version Management\n\n```csharp\n// Get current version\nvar currentVersion = await Electron.AutoUpdater.CurrentVersionAsync;\nConsole.WriteLine($\"Current version: {currentVersion}\");\n\n// Get update channel\nvar channel = await Electron.AutoUpdater.ChannelAsync;\nConsole.WriteLine($\"Update channel: {channel}\");\n\n// Set custom feed URL\n// Note: This would typically be configured in electron-builder.json\nvar feedUrl = await Electron.AutoUpdater.GetFeedURLAsync();\nConsole.WriteLine($\"Feed URL: {feedUrl}\");\n```\n\n## Related APIs\n\n- [Electron.App](App.md) - Application lifecycle events during updates\n- [Electron.Notification](Notification.md) - Notify users about update status\n- [Electron.Dialog](Dialog.md) - Show update confirmation dialogs\n\n## Additional Resources\n\n- [Electron AutoUpdater Documentation](https://electronjs.org/docs/api/auto-updater) - Official Electron auto-updater API\n"
  },
  {
    "path": "docs/API/Clipboard.md",
    "content": "# Electron.Clipboard\n\nPerform copy and paste operations on the system clipboard.\n\n## Overview\n\nThe `Electron.Clipboard` API provides comprehensive access to the system clipboard, supporting multiple data formats including text, HTML, RTF, images, and custom data. It enables reading from and writing to the clipboard with platform-specific behavior.\n\n## Methods\n\n#### 🧊 `Task<string[]> AvailableFormatsAsync(string type = \"\")`\nGet an array of supported formats for the clipboard type.\n\n**Parameters:**\n- `type` - Clipboard type\n\n**Returns:**\n\nAn array of supported formats for the clipboard type.\n\n#### 🧊 `void Clear(string type = \"\")`\nClears the clipboard content.\n\n**Parameters:**\n- `type` - Clipboard type\n\n#### 🧊 `Task<ReadBookmark> ReadBookmarkAsync()`\nReturns an Object containing title and url keys representing the bookmark in the clipboard. The title and url values will be empty strings when the bookmark is unavailable.\n\n**Returns:**\n\nObject containing title and url keys representing the bookmark in the clipboard.\n\n#### 🧊 `Task<string> ReadFindTextAsync()`\nmacOS: The text on the find pasteboard. This method uses synchronous IPC when called from the renderer process. The cached value is reread from the find pasteboard whenever the application is activated.\n\n**Returns:**\n\nThe text on the find pasteboard.\n\n#### 🧊 `Task<string> ReadHTMLAsync(string type = \"\")`\nRead the content in the clipboard as HTML markup.\n\n**Parameters:**\n- `type` - Clipboard type\n\n**Returns:**\n\nThe content in the clipboard as markup.\n\n#### 🧊 `Task<NativeImage> ReadImageAsync(string type = \"\")`\nRead an image from the clipboard.\n\n**Parameters:**\n- `type` - Clipboard type\n\n**Returns:**\n\nAn image from the clipboard.\n\n#### 🧊 `Task<string> ReadRTFAsync(string type = \"\")`\nRead the content in the clipboard as RTF.\n\n**Parameters:**\n- `type` - Clipboard type\n\n**Returns:**\n\nThe content in the clipboard as RTF.\n\n#### 🧊 `Task<string> ReadTextAsync(string type = \"\")`\nRead the content in the clipboard as plain text.\n\n**Parameters:**\n- `type` - Clipboard type\n\n**Returns:**\n\nThe content in the clipboard as plain text.\n\n#### 🧊 `void Write(Data data, string type = \"\")`\nWrites data to the clipboard.\n\n**Parameters:**\n- `data` - Data object to write\n- `type` - Clipboard type\n\n#### 🧊 `void WriteBookmark(string title, string url, string type = \"\")`\nWrites the title and url into the clipboard as a bookmark.\n\nNote: Most apps on Windows don't support pasting bookmarks into them so you can use clipboard.write to write both a bookmark and fallback text to the clipboard.\n\n**Parameters:**\n- `title` - Bookmark title\n- `url` - Bookmark URL\n- `type` - Clipboard type\n\n#### 🧊 `void WriteFindText(string text)`\nmacOS: Writes the text into the find pasteboard as plain text. This method uses synchronous IPC when called from the renderer process.\n\n**Parameters:**\n- `text` - Text to write to find pasteboard\n\n#### 🧊 `void WriteHTML(string markup, string type = \"\")`\nWrites markup to the clipboard.\n\n**Parameters:**\n- `markup` - HTML markup to write\n- `type` - Clipboard type\n\n#### 🧊 `void WriteImage(NativeImage image, string type = \"\")`\nWrites an image to the clipboard.\n\n**Parameters:**\n- `image` - Image to write to clipboard\n- `type` - Clipboard type\n\n#### 🧊 `void WriteRTF(string text, string type = \"\")`\nWrites the text into the clipboard in RTF.\n\n**Parameters:**\n- `text` - RTF content to write\n- `type` - Clipboard type\n\n#### 🧊 `void WriteText(string text, string type = \"\")`\nWrites the text into the clipboard as plain text.\n\n**Parameters:**\n- `text` - Text content to write\n- `type` - Clipboard type\n\n## Usage Examples\n\n### Basic Text Operations\n\n```csharp\n// Read text from clipboard\nvar text = await Electron.Clipboard.ReadTextAsync();\nConsole.WriteLine($\"Clipboard text: {text}\");\n\n// Write text to clipboard\nElectron.Clipboard.WriteText(\"Hello, Electron.NET!\");\n\n// Read with specific type\nvar html = await Electron.Clipboard.ReadHTMLAsync(\"public.main\");\n```\n\n### Rich Content Handling\n\n```csharp\n// Copy formatted text\nvar htmlContent = \"<h1>Title</h1><p>Some <strong>bold</strong> text</p>\";\nElectron.Clipboard.WriteHTML(htmlContent);\n\n// Read RTF content\nvar rtf = await Electron.Clipboard.ReadRTFAsync();\nConsole.WriteLine($\"RTF content: {rtf}\");\n```\n\n### Image Operations\n\n```csharp\n// Read image from clipboard\nvar image = await Electron.Clipboard.ReadImageAsync();\nif (image != null)\n{\n    Console.WriteLine($\"Image size: {image.Size.Width}x{image.Size.Height}\");\n}\n\n// Write image to clipboard\nvar nativeImage = NativeImage.CreateFromPath(\"screenshot.png\");\nElectron.Clipboard.WriteImage(nativeImage);\n```\n\n### Bookmark Management\n\n```csharp\n// Read bookmark from clipboard\nvar bookmark = await Electron.Clipboard.ReadBookmarkAsync();\nif (!string.IsNullOrEmpty(bookmark.Title))\n{\n    Console.WriteLine($\"Bookmark: {bookmark.Title} -> {bookmark.Url}\");\n}\n\n// Write bookmark to clipboard\nElectron.Clipboard.WriteBookmark(\"Electron.NET\", \"https://github.com/ElectronNET/Electron.NET\");\n```\n\n### Advanced Clipboard Operations\n\n```csharp\n// Check available formats\nvar formats = await Electron.Clipboard.AvailableFormatsAsync();\nConsole.WriteLine($\"Available formats: {string.Join(\", \", formats)}\");\n\n// Clear clipboard\nElectron.Clipboard.Clear();\n\n// Write custom data\nvar data = new Data\n{\n    Text = \"Custom data\",\n    Html = \"<p>Custom HTML</p>\",\n    Image = nativeImage\n};\nElectron.Clipboard.Write(data);\n```\n\n### macOS Find Pasteboard\n\n```csharp\n// macOS specific find pasteboard operations\nif (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n{\n    // Read find text\n    var findText = await Electron.Clipboard.ReadFindTextAsync();\n    Console.WriteLine($\"Find text: {findText}\");\n\n    // Write find text\n    Electron.Clipboard.WriteFindText(\"search term\");\n}\n```\n\n## Related APIs\n\n- [Electron.Shell](Shell.md) - Work with file paths from clipboard\n- [Electron.Notification](Notification.md) - Show clipboard operation results\n\n## Additional Resources\n\n- [Electron Clipboard Documentation](https://electronjs.org/docs/api/clipboard) - Official Electron clipboard API\n"
  },
  {
    "path": "docs/API/Dialog.md",
    "content": "# Electron.Dialog\n\nDisplay native system dialogs for opening and saving files, alerting, etc.\n\n## Overview\n\nThe `Electron.Dialog` API provides access to native system dialogs for file operations, message boxes, and certificate trust dialogs. These dialogs are modal and provide a consistent user experience across different platforms.\n\n## Methods\n\n#### 🧊 `Task<MessageBoxResult> ShowMessageBoxAsync(BrowserWindow browserWindow, MessageBoxOptions messageBoxOptions)`\nShows a message box, it will block the process until the message box is closed. It returns the index of the clicked button. If a callback is passed, the dialog will not block the process.\n\n**Parameters:**\n- `browserWindow` - The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.\n- `messageBoxOptions` - Message content and configuration\n\n**Returns:**\n\nThe API call will be asynchronous and the result will be passed via MessageBoxResult.\n\n#### 🧊 `Task<MessageBoxResult> ShowMessageBoxAsync(BrowserWindow browserWindow, string message)`\nShows a message box, it will block the process until the message box is closed. It returns the index of the clicked button. If a callback is passed, the dialog will not block the process.\n\n**Parameters:**\n- `browserWindow` - The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.\n- `message` - Message content\n\n**Returns:**\n\nThe API call will be asynchronous and the result will be passed via MessageBoxResult.\n\n#### 🧊 `Task<MessageBoxResult> ShowMessageBoxAsync(MessageBoxOptions messageBoxOptions)`\nShows a message box, it will block the process until the message box is closed. It returns the index of the clicked button. If a callback is passed, the dialog will not block the process.\n\n**Parameters:**\n- `messageBoxOptions` - Message content and configuration\n\n**Returns:**\n\nThe API call will be asynchronous and the result will be passed via MessageBoxResult.\n\n#### 🧊 `Task<MessageBoxResult> ShowMessageBoxAsync(string message)`\nShows a message box, it will block the process until the message box is closed. It returns the index of the clicked button. If a callback is passed, the dialog will not block the process.\n\n**Parameters:**\n- `message` - Message content\n\n**Returns:**\n\nThe API call will be asynchronous and the result will be passed via MessageBoxResult.\n\n#### 🧊 `Task<string[]> ShowOpenDialogAsync(BrowserWindow browserWindow, OpenDialogOptions options)`\nNote: On Windows and Linux an open dialog can not be both a file selector and a directory selector, so if you set properties to ['openFile', 'openDirectory'] on these platforms, a directory selector will be shown.\n\n**Parameters:**\n- `browserWindow` - The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.\n- `options` - Dialog configuration options\n\n**Returns:**\n\nAn array of file paths chosen by the user\n\n#### 🧊 `Task<string> ShowSaveDialogAsync(BrowserWindow browserWindow, SaveDialogOptions options)`\nDialog for save files.\n\n**Parameters:**\n- `browserWindow` - The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.\n- `options` - Dialog configuration options\n\n**Returns:**\n\nReturns String, the path of the file chosen by the user, if a callback is provided it returns an empty string.\n\n#### 🧊 `void ShowErrorBox(string title, string content)`\nDisplays a modal dialog that shows an error message.\n\nThis API can be called safely before the ready event the app module emits, it is usually used to report errors in early stage of startup.If called before the app readyevent on Linux, the message will be emitted to stderr, and no GUI dialog will appear.\n\n**Parameters:**\n- `title` - The title to display in the error box.\n- `content` - The text content to display in the error box.\n\n#### 🧊 `Task ShowCertificateTrustDialogAsync(BrowserWindow browserWindow, CertificateTrustDialogOptions options)`\nOn macOS, this displays a modal dialog that shows a message and certificate information, and gives the user the option of trusting/importing the certificate. If you provide a browserWindow argument the dialog will be attached to the parent window, making it modal.\n\n**Parameters:**\n- `browserWindow` - Parent window for modal behavior\n- `options` - Certificate trust dialog options\n\n#### 🧊 `Task ShowCertificateTrustDialogAsync(CertificateTrustDialogOptions options)`\nOn macOS, this displays a modal dialog that shows a message and certificate information, and gives the user the option of trusting/importing the certificate. If you provide a browserWindow argument the dialog will be attached to the parent window, making it modal.\n\n**Parameters:**\n- `options` - Certificate trust dialog options\n\n## Usage Examples\n\n### File Operations\n\n```csharp\n// Open multiple files\nvar files = await Electron.Dialog.ShowOpenDialogAsync(window, new OpenDialogOptions\n{\n    Properties = new[] { OpenDialogProperty.OpenFile, OpenDialogProperty.MultiSelections }\n});\n\n// Save with custom extension\nvar path = await Electron.Dialog.ShowSaveDialogAsync(window, new SaveDialogOptions\n{\n    DefaultPath = \"backup.json\",\n    Filters = new[] { new FileFilter { Name = \"JSON\", Extensions = new[] { \"json\" } } }\n});\n```\n\n### User Confirmation\n\n```csharp\n// Confirmation dialog\nvar result = await Electron.Dialog.ShowMessageBoxAsync(window, new MessageBoxOptions\n{\n    Type = MessageBoxType.Question,\n    Title = \"Confirm Delete\",\n    Message = $\"Delete {filename}?\",\n    Buttons = new[] { \"Cancel\", \"Delete\" },\n    DefaultId = 0,\n    CancelId = 0\n});\n\nif (result.Response == 1)\n{\n    // Delete file\n}\n```\n\n### Error Handling\n\n```csharp\n// Error dialog\nElectron.Dialog.ShowErrorBox(\"Save Failed\", \"Could not save file. Please check permissions and try again.\");\n\n// Warning dialog\nawait Electron.Dialog.ShowMessageBoxAsync(new MessageBoxOptions\n{\n    Type = MessageBoxType.Warning,\n    Title = \"Warning\",\n    Message = \"This operation may take several minutes.\",\n    Buttons = new[] { \"Continue\", \"Cancel\" }\n});\n```\n\n## Related APIs\n\n- [Electron.WindowManager](WindowManager.md) - Parent windows for modal dialogs\n- [Electron.App](App.md) - Application lifecycle events\n- [Electron.Shell](Shell.md) - File operations with selected paths\n\n## Additional Resources\n\n- [Electron Dialog Documentation](https://electronjs.org/docs/api/dialog) - Official Electron dialog API\n"
  },
  {
    "path": "docs/API/Dock.md",
    "content": "# Electron.Dock\n\nControl your app in the macOS dock.\n\n## Overview\n\nThe `Electron.Dock` API provides control over your application's appearance and behavior in the macOS dock. This includes bouncing the dock icon, setting badges, managing menus, and controlling visibility.\n\n## Properties\n\n#### 📋 `IReadOnlyCollection<MenuItem> MenuItems`\nGets a read-only collection of all current dock menu items.\n\n## Methods\n\n#### 🧊 `Task<int> BounceAsync(DockBounceType type, CancellationToken cancellationToken = default)`\nWhen `DockBounceType.Critical` is passed, the dock icon will bounce until either the application becomes active or the request is canceled. When `DockBounceType.Informational` is passed, the dock icon will bounce for one second. However, the request remains active until either the application becomes active or the request is canceled.\n\nNote: This method can only be used while the app is not focused; when the app is focused it will return -1.\n\n**Parameters:**\n- `type` - Can be critical or informational. The default is informational.\n- `cancellationToken` - The cancellation token\n\n**Returns:**\n\nAn ID representing the request.\n\n#### 🧊 `void CancelBounce(int id)`\nCancel the bounce of id.\n\n**Parameters:**\n- `id` - Id of the request\n\n#### 🧊 `void DownloadFinished(string filePath)`\nBounces the Downloads stack if the filePath is inside the Downloads folder.\n\n**Parameters:**\n- `filePath` - Path to the downloaded file\n\n#### 🧊 `Task<string> GetBadgeAsync(CancellationToken cancellationToken = default)`\nGets the string to be displayed in the dock's badging area.\n\n**Returns:**\n\nThe badge string of the dock.\n\n#### 🧊 `Task<Menu> GetMenu(CancellationToken cancellationToken = default)`\nGets the application's dock menu.\n\n**Returns:**\n\nThe application's dock menu.\n\n#### 🧊 `void Hide()`\nHides the dock icon.\n\n#### 🧊 `Task<bool> IsVisibleAsync(CancellationToken cancellationToken = default)`\nWhether the dock icon is visible. The app.dock.show() call is asynchronous so this method might not return true immediately after that call.\n\n**Returns:**\n\nWhether the dock icon is visible.\n\n#### 🧊 `void SetBadge(string text)`\nSets the string to be displayed in the dock's badging area.\n\n**Parameters:**\n- `text` - Badge text to display\n\n#### 🧊 `void SetIcon(string image)`\nSets the image associated with this dock icon.\n\n**Parameters:**\n- `image` - Icon image path\n\n#### 🧊 `void SetMenu(MenuItem[] menuItems)`\nSets the application's dock menu.\n\n**Parameters:**\n- `menuItems` - Array of menu items for the dock menu\n\n#### 🧊 `void Show()`\nShows the dock icon.\n\n## Usage Examples\n\n### Basic Dock Operations\n\n```csharp\n// Hide/Show dock icon\nElectron.Dock.Hide();\nawait Task.Delay(2000);\nElectron.Dock.Show();\n\n// Check visibility\nvar isVisible = await Electron.Dock.IsVisibleAsync();\nConsole.WriteLine($\"Dock visible: {isVisible}\");\n```\n\n### Badge Notifications\n\n```csharp\n// Set badge count\nElectron.Dock.SetBadge(\"5\");\n\n// Get current badge\nvar badge = await Electron.Dock.GetBadgeAsync();\nConsole.WriteLine($\"Current badge: {badge}\");\n\n// Clear badge\nElectron.Dock.SetBadge(\"\");\n```\n\n### Dock Icon Animation\n\n```csharp\n// Bounce for attention\nvar bounceId = await Electron.Dock.BounceAsync(DockBounceType.Critical);\nConsole.WriteLine($\"Bounce ID: {bounceId}\");\n\n// Cancel bounce after 3 seconds\nawait Task.Delay(3000);\nElectron.Dock.CancelBounce(bounceId);\n\n// Informational bounce\nawait Electron.Dock.BounceAsync(DockBounceType.Informational);\n```\n\n### Dock Menu\n\n```csharp\n// Create dock menu\nvar dockMenuItems = new[]\n{\n    new MenuItem { Label = \"Show Window\", Click = () => ShowMainWindow() },\n    new MenuItem { Label = \"Settings\", Click = () => OpenSettings() },\n    new MenuItem { Type = MenuType.Separator },\n    new MenuItem { Label = \"Exit\", Click = () => Electron.App.Quit() }\n};\n\n// Set dock menu\nElectron.Dock.SetMenu(dockMenuItems);\n\n// Get current menu\nvar currentMenu = await Electron.Dock.GetMenu();\nConsole.WriteLine($\"Menu items: {Electron.Dock.MenuItems.Count}\");\n```\n\n### Download Notifications\n\n```csharp\n// Notify about completed download\nvar downloadPath = \"/Users/username/Downloads/document.pdf\";\nElectron.Dock.DownloadFinished(downloadPath);\n```\n\n### Custom Dock Icon\n\n```csharp\n// Set custom dock icon\nElectron.Dock.SetIcon(\"assets/custom-dock-icon.png\");\n\n// Set icon based on status\nif (isConnected)\n{\n    Electron.Dock.SetIcon(\"assets/connected-icon.png\");\n}\nelse\n{\n    Electron.Dock.SetIcon(\"assets/disconnected-icon.png\");\n}\n```\n\n### Application Integration\n\n```csharp\n// Update dock badge based on unread count\nUpdateDockBadge(unreadMessageCount);\n\nvoid UpdateDockBadge(int count)\n{\n    if (count > 0)\n    {\n        Electron.Dock.SetBadge(count.ToString());\n    }\n    else\n    {\n        Electron.Dock.SetBadge(\"\");\n    }\n}\n\n// Animate dock when receiving message\nprivate async void OnMessageReceived()\n{\n    await Electron.Dock.BounceAsync(DockBounceType.Informational);\n    Electron.Dock.SetBadge((unreadCount + 1).ToString());\n}\n```\n\n## Related APIs\n\n- [Electron.App](App.md) - Application lifecycle events\n- [Electron.Notification](Notification.md) - Desktop notifications\n- [Electron.Menu](Menu.md) - Menu items for dock menu\n\n## Additional Resources\n\n- [Electron Dock Documentation](https://electronjs.org/docs/api/dock) - Official Electron dock API\n"
  },
  {
    "path": "docs/API/GlobalShortcut.md",
    "content": "# Electron.GlobalShortcut\n\nRegister global keyboard shortcuts that work even when the application is not focused.\n\n## Overview\n\nThe `Electron.GlobalShortcut` API provides the ability to register global keyboard shortcuts that can be triggered even when the application does not have keyboard focus. This is useful for creating system-wide hotkeys and shortcuts.\n\n## Methods\n\n#### 🧊 `Task<bool> IsRegisteredAsync(string accelerator)`\nCheck if the accelerator is registered.\n\n**Parameters:**\n- `accelerator` - Keyboard shortcut to check\n\n**Returns:**\n\nWhether this application has registered the accelerator.\n\n#### 🧊 `void Register(string accelerator, Action function)`\nRegisters a global shortcut of accelerator. The callback is called when the registered shortcut is pressed by the user.\n\n**Parameters:**\n- `accelerator` - Keyboard shortcut combination\n- `function` - Callback function to execute when shortcut is pressed\n\n#### 🧊 `void Unregister(string accelerator)`\nUnregisters the global shortcut of accelerator.\n\n**Parameters:**\n- `accelerator` - Keyboard shortcut to unregister\n\n#### 🧊 `void UnregisterAll()`\nUnregisters all of the global shortcuts.\n\n## Usage Examples\n\n### Basic Global Shortcuts\n\n```csharp\n// Register global shortcuts\nElectron.GlobalShortcut.Register(\"CommandOrControl+N\", () =>\n{\n    CreateNewDocument();\n});\n\nElectron.GlobalShortcut.Register(\"CommandOrControl+O\", () =>\n{\n    OpenDocument();\n});\n\nElectron.GlobalShortcut.Register(\"CommandOrControl+S\", () =>\n{\n    SaveDocument();\n});\n```\n\n### Media Control Shortcuts\n\n```csharp\n// Media playback shortcuts\nElectron.GlobalShortcut.Register(\"MediaPlayPause\", () =>\n{\n    TogglePlayback();\n});\n\nElectron.GlobalShortcut.Register(\"MediaNextTrack\", () =>\n{\n    NextTrack();\n});\n\nElectron.GlobalShortcut.Register(\"MediaPreviousTrack\", () =>\n{\n    PreviousTrack();\n});\n```\n\n### Application Control Shortcuts\n\n```csharp\n// Application control shortcuts\nElectron.GlobalShortcut.Register(\"CommandOrControl+Shift+Q\", async () =>\n{\n    var result = await Electron.Dialog.ShowMessageBoxAsync(\"Quit Application?\", \"Are you sure you want to quit?\");\n    if (result.Response == 1) // Yes\n    {\n        Electron.App.Quit();\n    }\n});\n\nElectron.GlobalShortcut.Register(\"CommandOrControl+Shift+H\", () =>\n{\n    ToggleMainWindow();\n});\n```\n\n### Dynamic Shortcut Management\n\n```csharp\n// Register shortcuts based on user preferences\npublic void RegisterUserShortcuts(Dictionary<string, Action> shortcuts)\n{\n    foreach (var shortcut in shortcuts)\n    {\n        Electron.GlobalShortcut.Register(shortcut.Key, shortcut.Value);\n    }\n}\n\n// Check if shortcut is available\npublic async Task<bool> IsShortcutAvailable(string accelerator)\n{\n    return await Electron.GlobalShortcut.IsRegisteredAsync(accelerator);\n}\n\n// Unregister specific shortcut\npublic void UnregisterShortcut(string accelerator)\n{\n    Electron.GlobalShortcut.Unregister(accelerator);\n}\n```\n\n### Platform-Specific Shortcuts\n\n```csharp\n// macOS specific shortcuts\nif (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n{\n    Electron.GlobalShortcut.Register(\"Command+Comma\", () =>\n    {\n        OpenPreferences();\n    });\n\n    Electron.GlobalShortcut.Register(\"Command+H\", () =>\n    {\n        Electron.App.Hide();\n    });\n}\n\n// Windows/Linux shortcuts\nelse\n{\n    Electron.GlobalShortcut.Register(\"Ctrl+Shift+P\", () =>\n    {\n        OpenPreferences();\n    });\n\n    Electron.GlobalShortcut.Register(\"Alt+F4\", () =>\n    {\n        Electron.App.Quit();\n    });\n}\n```\n\n### Shortcut Validation\n\n```csharp\n// Validate shortcuts before registration\npublic async Task<bool> TryRegisterShortcut(string accelerator, Action callback)\n{\n    if (await Electron.GlobalShortcut.IsRegisteredAsync(accelerator))\n    {\n        Console.WriteLine($\"Shortcut {accelerator} is already registered\");\n        return false;\n    }\n\n    try\n    {\n        Electron.GlobalShortcut.Register(accelerator, callback);\n        Console.WriteLine($\"Successfully registered shortcut: {accelerator}\");\n        return true;\n    }\n    catch (Exception ex)\n    {\n        Console.WriteLine($\"Failed to register shortcut {accelerator}: {ex.Message}\");\n        return false;\n    }\n}\n```\n\n## Related APIs\n\n- [Electron.App](App.md) - Application lifecycle events\n- [Electron.Menu](Menu.md) - Menu-based shortcuts\n- [Electron.WindowManager](WindowManager.md) - Window focus management\n\n## Additional Resources\n\n- [Electron GlobalShortcut Documentation](https://electronjs.org/docs/api/global-shortcut) - Official Electron global shortcut API\n"
  },
  {
    "path": "docs/API/HostHook.md",
    "content": "# Electron.HostHook\n\nExecute native JavaScript/TypeScript code from the host process.\n\n## Overview\n\nThe `Electron.HostHook` API allows you to execute native JavaScript/TypeScript code from the host process. This enables advanced integration scenarios where you need to run custom JavaScript code or access Node.js APIs directly.\n\n## Methods\n\n#### 🧊 `void Call(string socketEventName, params dynamic[] arguments)`\nExecute native JavaScript/TypeScript code synchronously.\n\n**Parameters:**\n- `socketEventName` - Socket name registered on the host\n- `arguments` - Optional parameters\n\n#### 🧊 `Task<T> CallAsync<T>(string socketEventName, params dynamic[] arguments)`\nExecute native JavaScript/TypeScript code asynchronously with type-safe return values.\n\n**Parameters:**\n- `T` - Expected return type\n- `socketEventName` - Socket name registered on the host\n- `arguments` - Optional parameters\n\n**Returns:**\n\nTask<T> with the result from the executed host code.\n\n## Usage Examples\n\n### Basic Host Hook Execution\n\n```csharp\n// Execute simple JavaScript function\nElectron.HostHook.Call(\"myFunction\", \"parameter1\", 42);\n\n// Execute with callback-style result\nvar result = await Electron.HostHook.CallAsync<string>(\"getUserName\", userId);\nConsole.WriteLine($\"User name: {result}\");\n```\n\n### Advanced Integration\n\n```csharp\n// Call custom Electron API\nvar fileContent = await Electron.HostHook.CallAsync<string>(\"readFile\", \"config.json\");\nConsole.WriteLine($\"Config: {fileContent}\");\n\n// Execute with multiple parameters\nvar processedData = await Electron.HostHook.CallAsync<object[]>(\"processData\", rawData, options);\n\n// Call with complex objects\nvar settings = new { theme = \"dark\", language = \"en\" };\nvar updatedSettings = await Electron.HostHook.CallAsync<object>(\"updateSettings\", settings);\n```\n\n### Error Handling\n\n```csharp\ntry\n{\n    // Execute host function with error handling\n    var result = await Electron.HostHook.CallAsync<string>(\"riskyOperation\", inputData);\n    Console.WriteLine($\"Success: {result}\");\n}\ncatch (Exception ex)\n{\n    // Handle execution errors\n    Console.WriteLine($\"Host hook error: {ex.Message}\");\n    Electron.Dialog.ShowErrorBox(\"Operation Failed\", \"Could not execute host function.\");\n}\n```\n\n### Type-Safe Operations\n\n```csharp\n// Strongly typed return values\nvar userInfo = await Electron.HostHook.CallAsync<UserInfo>(\"getUserInfo\", userId);\nConsole.WriteLine($\"User: {userInfo.Name}, Email: {userInfo.Email}\");\n\n// Array results\nvar fileList = await Electron.HostHook.CallAsync<string[]>(\"listFiles\", directoryPath);\nforeach (var file in fileList)\n{\n    Console.WriteLine($\"File: {file}\");\n}\n\n// Complex object results\nvar systemStats = await Electron.HostHook.CallAsync<SystemStatistics>(\"getSystemStats\");\nConsole.WriteLine($\"CPU: {systemStats.CpuUsage}%, Memory: {systemStats.MemoryUsage}%\");\n```\n\n### Custom ElectronHostHook Setup\n\n```csharp\n// In your ElectronHostHook/index.ts\nimport { app } from 'electron';\n\nexport function getAppVersion(): string {\n    return app.getVersion();\n}\n\nexport async function readConfigFile(): Promise<string> {\n    const fs = require('fs').promises;\n    return await fs.readFile('config.json', 'utf8');\n}\n\nexport function customNotification(message: string): void {\n    // Custom notification logic\n    console.log(`Custom notification: ${message}`);\n}\n```\n\n### Integration with .NET Code\n\n```csharp\n// Use host hook in your application logic\npublic async Task<string> GetApplicationVersion()\n{\n    return await Electron.HostHook.CallAsync<string>(\"getAppVersion\");\n}\n\npublic async Task LoadConfiguration()\n{\n    try\n    {\n        var config = await Electron.HostHook.CallAsync<ConfigObject>(\"readConfigFile\");\n        ApplyConfiguration(config);\n    }\n    catch (Exception ex)\n    {\n        Console.WriteLine($\"Failed to load config: {ex.Message}\");\n        UseDefaultConfiguration();\n    }\n}\n\npublic void ShowCustomNotification(string message)\n{\n    Electron.HostHook.Call(\"customNotification\", message);\n}\n```\n\n## Related APIs\n\n- [Electron.IpcMain](IpcMain.md) - Inter-process communication\n- [Electron.App](App.md) - Application lifecycle events\n- [Electron.WebContents](WebContents.md) - Web content integration\n\n## Additional Resources\n\n- [Host Hook Documentation](../Core/Advanced-Migration-Topics.md) - Setting up custom host hooks\n"
  },
  {
    "path": "docs/API/IpcMain.md",
    "content": "# Electron.IpcMain\n\nCommunicate asynchronously from the main process to renderer processes.\n\n## Overview\n\nThe `Electron.IpcMain` API provides inter-process communication between the main process and renderer processes. It allows you to send messages, listen for events, and handle communication between different parts of your Electron application.\n\n## Methods\n\n#### 🧊 `Task On(string channel, Action<object> listener)`\nListens to channel, when a new message arrives listener would be called with listener(event, args...).\n\n**Parameters:**\n- `channel` - Channel name to listen on\n- `listener` - Callback method to handle incoming messages\n\n#### 🧊 `void OnSync(string channel, Func<object, object> listener)`\nSend a message to the renderer process synchronously via channel. Note: Sending a synchronous message will block the whole renderer process.\n\n**Parameters:**\n- `channel` - Channel name to listen on\n- `listener` - Synchronous callback method\n\n#### 🧊 `void Once(string channel, Action<object> listener)`\nAdds a one time listener method for the event. This listener is invoked only the next time a message is sent to channel, after which it is removed.\n\n**Parameters:**\n- `channel` - Channel name to listen on\n- `listener` - Callback method to handle the message once\n\n#### 🧊 `void RemoveAllListeners(string channel)`\nRemoves all listeners of the specified channel.\n\n**Parameters:**\n- `channel` - Channel name to remove listeners from\n\n#### 🧊 `void Send(BrowserView browserView, string channel, params object[] data)`\nSend a message to the BrowserView renderer process asynchronously via channel.\n\n**Parameters:**\n- `browserView` - Target browser view\n- `channel` - Channel name to send on\n- `data` - Arguments to send\n\n#### 🧊 `void Send(BrowserWindow browserWindow, string channel, params object[] data)`\nSend a message to the renderer process asynchronously via channel.\n\n**Parameters:**\n- `browserWindow` - Target browser window\n- `channel` - Channel name to send on\n- `data` - Arguments to send\n\n## Usage Examples\n\n### Basic Message Handling\n\n```csharp\n// Listen for messages from renderer\nawait Electron.IpcMain.On(\"request-data\", (args) =>\n{\n    Console.WriteLine($\"Received request: {args}\");\n    // Process the request and send response\n});\n\n// Send response back to renderer\nElectron.IpcMain.Send(mainWindow, \"data-response\", processedData);\n```\n\n### Synchronous Communication\n\n```csharp\n// Handle synchronous requests\nElectron.IpcMain.OnSync(\"get-user-info\", (request) =>\n{\n    var userId = request.ToString();\n    var userInfo = GetUserInfo(userId);\n    return userInfo;\n});\n```\n\n### One-time Event Handling\n\n```csharp\n// Handle initialization request once\nElectron.IpcMain.Once(\"app-initialized\", (args) =>\n{\n    Console.WriteLine(\"App initialized, setting up...\");\n    InitializeApplication();\n});\n```\n\n### Complex Data Exchange\n\n```csharp\n// Send complex data to renderer\nvar appData = new\n{\n    Version = \"1.0.0\",\n    Features = new[] { \"feature1\", \"feature2\" },\n    Settings = new { Theme = \"dark\", Language = \"en\" }\n};\n\nElectron.IpcMain.Send(mainWindow, \"app-config\", appData);\n\n// Listen for settings updates\nawait Electron.IpcMain.On(\"update-settings\", (settings) =>\n{\n    var config = JsonConvert.DeserializeObject<AppSettings>(settings.ToString());\n    ApplySettings(config);\n});\n```\n\n### Multi-Window Communication\n\n```csharp\n// Send message to specific window\nvar settingsWindow = await Electron.WindowManager.CreateWindowAsync();\nElectron.IpcMain.Send(settingsWindow, \"show-settings\", currentSettings);\n\n// Broadcast to all windows\nforeach (var window in Electron.WindowManager.BrowserWindows)\n{\n    Electron.IpcMain.Send(window, \"notification\", message);\n}\n```\n\n### Error Handling\n\n```csharp\n// Handle IPC errors gracefully\nawait Electron.IpcMain.On(\"risky-operation\", async (args) =>\n{\n    try\n    {\n        var result = await PerformRiskyOperation(args);\n        Electron.IpcMain.Send(mainWindow, \"operation-success\", result);\n    }\n    catch (Exception ex)\n    {\n        Electron.IpcMain.Send(mainWindow, \"operation-error\", ex.Message);\n    }\n});\n```\n\n### Integration with Host Hooks\n\n```csharp\n// Use with custom host functionality\nawait Electron.IpcMain.On(\"execute-host-function\", async (args) =>\n{\n    var functionName = args.ToString();\n    var result = await Electron.HostHook.CallAsync<string>(functionName);\n\n    Electron.IpcMain.Send(mainWindow, \"function-result\", result);\n});\n```\n\n## Related APIs\n\n- [Electron.HostHook](HostHook.md) - Execute custom JavaScript functions\n- [Electron.WindowManager](WindowManager.md) - Target specific windows for communication\n- [Electron.WebContents](WebContents.md) - Send messages to web content\n\n## Additional Resources\n\n- [Electron IPC Documentation](https://electronjs.org/docs/api/ipc-main) - Official Electron IPC API\n"
  },
  {
    "path": "docs/API/Menu.md",
    "content": "# Electron.Menu\n\nCreate application menus, context menus, and menu items with full keyboard shortcut support.\n\n## Overview\n\nThe `Electron.Menu` API provides comprehensive control over application menus and context menus. It supports native platform menus with custom menu items, submenus, keyboard shortcuts, and role-based menu items.\n\n## Properties\n\n#### 📋 `IReadOnlyDictionary<int, ReadOnlyCollection<MenuItem>> ContextMenuItems`\nGets a read-only dictionary of all current context menu items, keyed by browser window ID.\n\n#### 📋 `IReadOnlyCollection<MenuItem> MenuItems`\nGets a read-only collection of all current application menu items.\n\n## Methods\n\n#### 🧊 `void ContextMenuPopup(BrowserWindow browserWindow)`\nShows the context menu for the specified browser window.\n\n**Parameters:**\n- `browserWindow` - The browser window to show the context menu for\n\n#### 🧊 `void SetApplicationMenu(MenuItem[] menuItems)`\nSets the application menu for the entire application.\n\n**Parameters:**\n- `menuItems` - Array of MenuItem objects defining the application menu\n\n#### 🧊 `void SetContextMenu(BrowserWindow browserWindow, MenuItem[] menuItems)`\nSets a context menu for a specific browser window.\n\n**Parameters:**\n- `browserWindow` - The browser window to attach the context menu to\n- `menuItems` - Array of MenuItem objects defining the context menu\n\n## Usage Examples\n\n### Application Menu\n\n```csharp\n// Create application menu\nvar menuItems = new[]\n{\n    new MenuItem\n    {\n        Label = \"File\",\n        Submenu = new[]\n        {\n            new MenuItem { Label = \"New\", Click = () => CreateNewDocument() },\n            new MenuItem { Label = \"Open\", Click = () => OpenDocument() },\n            new MenuItem { Type = MenuType.Separator },\n            new MenuItem { Label = \"Exit\", Click = () => Electron.App.Quit() }\n        }\n    },\n    new MenuItem\n    {\n        Label = \"Edit\",\n        Submenu = new[]\n        {\n            new MenuItem { Role = MenuRole.Undo },\n            new MenuItem { Role = MenuRole.Redo },\n            new MenuItem { Type = MenuType.Separator },\n            new MenuItem { Role = MenuRole.Cut },\n            new MenuItem { Role = MenuRole.Copy },\n            new MenuItem { Role = MenuRole.Paste }\n        }\n    },\n    new MenuItem\n    {\n        Label = \"View\",\n        Submenu = new[]\n        {\n            new MenuItem { Role = MenuRole.Reload },\n            new MenuItem { Role = MenuRole.ForceReload },\n            new MenuItem { Role = MenuRole.ToggleDevTools },\n            new MenuItem { Type = MenuType.Separator },\n            new MenuItem { Role = MenuRole.ResetZoom },\n            new MenuItem { Role = MenuRole.ZoomIn },\n            new MenuItem { Role = MenuRole.ZoomOut }\n        }\n    },\n    new MenuItem\n    {\n        Label = \"Window\",\n        Submenu = new[]\n        {\n            new MenuItem { Role = MenuRole.Minimize },\n            new MenuItem { Role = MenuRole.Close }\n        }\n    }\n};\n\n// Set application menu\nElectron.Menu.SetApplicationMenu(menuItems);\n```\n\n### Context Menu\n\n```csharp\n// Create context menu for specific window\nvar contextMenuItems = new[]\n{\n    new MenuItem { Label = \"Copy\", Click = () => CopySelectedText() },\n    new MenuItem { Label = \"Paste\", Click = () => PasteText() },\n    new MenuItem { Type = MenuType.Separator },\n    new MenuItem { Label = \"Inspect Element\", Click = () => InspectElement() }\n};\n\n// Set context menu for window\nElectron.Menu.SetContextMenu(mainWindow, contextMenuItems);\n\n// Show context menu programmatically\nElectron.Menu.ContextMenuPopup(mainWindow);\n```\n\n### Menu with Keyboard Shortcuts\n\n```csharp\n// Create menu with keyboard shortcuts\nvar menuItems = new[]\n{\n    new MenuItem\n    {\n        Label = \"File\",\n        Submenu = new[]\n        {\n            new MenuItem\n            {\n                Label = \"New\",\n                Accelerator = \"CmdOrCtrl+N\",\n                Click = () => CreateNewDocument()\n            },\n            new MenuItem\n            {\n                Label = \"Open\",\n                Accelerator = \"CmdOrCtrl+O\",\n                Click = () => OpenDocument()\n            },\n            new MenuItem\n            {\n                Label = \"Save\",\n                Accelerator = \"CmdOrCtrl+S\",\n                Click = () => SaveDocument()\n            }\n        }\n    }\n};\n\nElectron.Menu.SetApplicationMenu(menuItems);\n```\n\n### Dynamic Menu Updates\n\n```csharp\n// Update menu items dynamically\nvar fileMenu = Electron.Menu.MenuItems.FirstOrDefault(m => m.Label == \"File\");\nif (fileMenu?.Submenu != null)\n{\n    var saveItem = fileMenu.Submenu.FirstOrDefault(m => m.Label == \"Save\");\n    if (saveItem != null)\n    {\n        saveItem.Enabled = HasUnsavedChanges;\n    }\n}\n```\n\n### Platform-Specific Menus\n\n```csharp\n// macOS specific menu items\nif (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n{\n    var macMenuItems = new[]\n    {\n        new MenuItem\n        {\n            Label = \"MyApp\",\n            Submenu = new[]\n            {\n                new MenuItem { Role = MenuRole.About },\n                new MenuItem { Type = MenuType.Separator },\n                new MenuItem { Role = MenuRole.Services },\n                new MenuItem { Type = MenuType.Separator },\n                new MenuItem { Role = MenuRole.Hide },\n                new MenuItem { Role = MenuRole.HideOthers },\n                new MenuItem { Role = MenuRole.Unhide },\n                new MenuItem { Type = MenuType.Separator },\n                new MenuItem { Role = MenuRole.Quit }\n            }\n        }\n    };\n\n    // Insert before File menu\n    var allMenus = new List<MenuItem>(macMenuItems);\n    allMenus.AddRange(menuItems);\n    Electron.Menu.SetApplicationMenu(allMenus.ToArray());\n}\n```\n\n## Related APIs\n\n- [Electron.WindowManager](WindowManager.md) - Windows for context menus\n- [Electron.App](App.md) - Application lifecycle events\n- [Electron.GlobalShortcut](GlobalShortcut.md) - Global keyboard shortcuts\n\n## Additional Resources\n\n- [Electron Menu Documentation](https://electronjs.org/docs/api/menu) - Official Electron menu API\n"
  },
  {
    "path": "docs/API/NativeTheme.md",
    "content": "# Electron.NativeTheme\n\nDetect and respond to changes in Chromium's native color theme.\n\n## Overview\n\nThe `Electron.NativeTheme` API provides access to Chromium's native color theme information and allows you to detect and respond to changes in the system's dark/light mode settings. This enables your application to automatically adapt to the user's theme preferences.\n\n## Methods\n\n#### 🧊 `Task<ThemeSourceMode> GetThemeSourceAsync()`\nGet the current theme source setting.\n\n**Returns:**\n\nA `ThemeSourceMode` property that can be `ThemeSourceMode.System`, `ThemeSourceMode.Light` or `ThemeSourceMode.Dark`.\n\n#### 🧊 `void SetThemeSource(ThemeSourceMode themeSourceMode)`\nSetting this property to `ThemeSourceMode.System` will remove the override and everything will be reset to the OS default. By default 'ThemeSource' is `ThemeSourceMode.System`.\n\n**Parameters:**\n- `themeSourceMode` - The new ThemeSource\n\n#### 🧊 `Task<bool> ShouldUseDarkColorsAsync()`\nCheck if the system is currently using dark colors.\n\n**Returns:**\n\nA bool for if the OS / Chromium currently has a dark mode enabled or is being instructed to show a dark-style UI.\n\n#### 🧊 `Task<bool> ShouldUseHighContrastColorsAsync()`\nCheck if the system is currently using high contrast colors.\n\n**Returns:**\n\nA bool for if the OS / Chromium currently has high-contrast mode enabled or is being instructed to show a high-contrast UI.\n\n#### 🧊 `Task<bool> ShouldUseInvertedColorSchemeAsync()`\nCheck if the system is currently using an inverted color scheme.\n\n**Returns:**\n\nA bool for if the OS / Chromium currently has an inverted color scheme or is being instructed to use an inverted color scheme.\n\n## Events\n\n#### ⚡ `Updated`\nEmitted when something in the underlying NativeTheme has changed. This normally means that either the value of ShouldUseDarkColorsAsync, ShouldUseHighContrastColorsAsync or ShouldUseInvertedColorSchemeAsync has changed.\n\n## Usage Examples\n\n### Basic Theme Detection\n\n```csharp\n// Check current theme\nvar isDarkMode = await Electron.NativeTheme.ShouldUseDarkColorsAsync();\nConsole.WriteLine($\"Dark mode: {isDarkMode}\");\n\n// Get current theme source\nvar themeSource = await Electron.NativeTheme.GetThemeSourceAsync();\nConsole.WriteLine($\"Theme source: {themeSource}\");\n```\n\n### Theme Change Monitoring\n\n```csharp\n// Monitor theme changes\nElectron.NativeTheme.Updated += () =>\n{\n    Console.WriteLine(\"Theme updated\");\n    UpdateApplicationTheme();\n};\n\nasync void UpdateApplicationTheme()\n{\n    var isDarkMode = await Electron.NativeTheme.ShouldUseDarkColorsAsync();\n    var isHighContrast = await Electron.NativeTheme.ShouldUseHighContrastColorsAsync();\n\n    // Update application appearance\n    ApplyTheme(isDarkMode, isHighContrast);\n}\n```\n\n### Manual Theme Control\n\n```csharp\n// Force dark theme\nElectron.NativeTheme.SetThemeSource(ThemeSourceMode.Dark);\n\n// Force light theme\nElectron.NativeTheme.SetThemeSource(ThemeSourceMode.Light);\n\n// Follow system theme\nElectron.NativeTheme.SetThemeSource(ThemeSourceMode.System);\n```\n\n### Application Theme Integration\n\n```csharp\npublic async Task InitializeThemeSupport()\n{\n    // Set initial theme based on system preference\n    var isDarkMode = await Electron.NativeTheme.ShouldUseDarkColorsAsync();\n    ApplyTheme(isDarkMode);\n\n    // Monitor theme changes\n    Electron.NativeTheme.Updated += async () =>\n    {\n        var darkMode = await Electron.NativeTheme.ShouldUseDarkColorsAsync();\n        ApplyTheme(darkMode);\n    };\n}\n\nprivate void ApplyTheme(bool isDarkMode)\n{\n    if (isDarkMode)\n    {\n        // Apply dark theme\n        SetDarkThemeColors();\n        UpdateWindowTheme(\"dark\");\n    }\n    else\n    {\n        // Apply light theme\n        SetLightThemeColors();\n        UpdateWindowTheme(\"light\");\n    }\n}\n```\n\n### Advanced Theme Management\n\n```csharp\n// Check all theme properties\nvar isDarkMode = await Electron.NativeTheme.ShouldUseDarkColorsAsync();\nvar isHighContrast = await Electron.NativeTheme.ShouldUseHighContrastColorsAsync();\nvar isInverted = await Electron.NativeTheme.ShouldUseInvertedColorSchemeAsync();\n\nConsole.WriteLine($\"Dark mode: {isDarkMode}\");\nConsole.WriteLine($\"High contrast: {isHighContrast}\");\nConsole.WriteLine($\"Inverted: {isInverted}\");\n\n// Apply appropriate theme\nif (isHighContrast)\n{\n    ApplyHighContrastTheme();\n}\nelse if (isDarkMode)\n{\n    ApplyDarkTheme();\n}\nelse\n{\n    ApplyLightTheme();\n}\n```\n\n### Theme-Aware Window Creation\n\n```csharp\n// Create window with theme-appropriate settings\nvar isDarkMode = await Electron.NativeTheme.ShouldUseDarkColorsAsync();\n\nvar windowOptions = new BrowserWindowOptions\n{\n    Width = 1200,\n    Height = 800,\n    Title = \"My Application\",\n    BackgroundColor = isDarkMode ? \"#1a1a1a\" : \"#ffffff\",\n    WebPreferences = new WebPreferences\n    {\n        // Additional web preferences based on theme\n    }\n};\n\nvar window = await Electron.WindowManager.CreateWindowAsync(windowOptions);\n```\n\n## Related APIs\n\n- [Electron.WindowManager](WindowManager.md) - Apply theme to windows\n- [Electron.Screen](Screen.md) - Screen-related theme considerations\n- [Electron.App](App.md) - Application-level theme events\n\n## Additional Resources\n\n- [Electron NativeTheme Documentation](https://electronjs.org/docs/api/native-theme) - Official Electron native theme API\n- [Theme Support](../Core/What's-New.md) - Understanding theme functionality\n- [User Experience](../Using/Configuration.md) - Design theme-aware applications\n"
  },
  {
    "path": "docs/API/Notification.md",
    "content": "# Electron.Notification\n\nShow native desktop notifications with custom content and actions.\n\n## Overview\n\nThe `Electron.Notification` API provides the ability to show native desktop notifications with custom titles, bodies, icons, and actions. Notifications work across Windows, macOS, and Linux with platform-specific behavior.\n\n## Methods\n\n#### 🧊 `Task<bool> IsSupportedAsync()`\nCheck if desktop notifications are supported on the current platform.\n\n**Returns:**\n\nWhether or not desktop notifications are supported on the current system.\n\n#### 🧊 `void Show(NotificationOptions notificationOptions)`\nCreate OS desktop notifications with the specified options.\n\n**Parameters:**\n- `notificationOptions` - Notification configuration options\n\n## Usage Examples\n\n### Basic Notification\n\n```csharp\n// Simple notification\nElectron.Notification.Show(new NotificationOptions\n{\n    Title = \"My Application\",\n    Body = \"This is a notification message\",\n    Icon = \"assets/notification-icon.png\"\n});\n```\n\n### Notification with Actions\n\n```csharp\n// Notification with reply action\nElectron.Notification.Show(new NotificationOptions\n{\n    Title = \"New Message\",\n    Body = \"You have a new message from John\",\n    Icon = \"assets/message-icon.png\",\n    Actions = new[]\n    {\n        new NotificationAction { Text = \"Reply\", Type = NotificationActionType.Button },\n        new NotificationAction { Text = \"View\", Type = NotificationActionType.Button }\n    },\n    OnClick = () => OpenMessageWindow(),\n    OnAction = (action) =>\n    {\n        if (action == \"Reply\")\n        {\n            ShowReplyDialog();\n        }\n        else if (action == \"View\")\n        {\n            OpenMessageWindow();\n        }\n    }\n});\n```\n\n### Rich Notifications\n\n```csharp\n// Rich notification with all options\nElectron.Notification.Show(new NotificationOptions\n{\n    Title = \"Download Complete\",\n    Subtitle = \"Your file has finished downloading\",\n    Body = \"document.pdf has been downloaded to your Downloads folder.\",\n    Icon = \"assets/download-icon.png\",\n    ImageUrl = \"file://\" + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, \"assets/preview.png\"),\n    Sound = NotificationSound.Default,\n    Urgency = NotificationUrgency.Normal,\n    Category = \"transfer.complete\",\n    Tag = \"download-123\",\n    Actions = new[]\n    {\n        new NotificationAction { Text = \"Open\", Type = NotificationActionType.Button },\n        new NotificationAction { Text = \"Show in Folder\", Type = NotificationActionType.Button }\n    },\n    OnShow = () => Console.WriteLine(\"Notification shown\"),\n    OnClick = () => OpenDownloadedFile(),\n    OnClose = () => Console.WriteLine(\"Notification closed\"),\n    OnAction = (action) =>\n    {\n        if (action == \"Open\")\n        {\n            OpenDownloadedFile();\n        }\n        else if (action == \"Show in Folder\")\n        {\n            ShowInFolder();\n        }\n    }\n});\n```\n\n### Platform-Specific Notifications\n\n```csharp\n// Windows toast notification\nif (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n{\n    Electron.Notification.Show(new NotificationOptions\n    {\n        Title = \"Background Task\",\n        Body = \"Your backup is complete\",\n        Icon = \"assets/app-icon.ico\",\n        Tag = \"backup-complete\",\n        RequireInteraction = true\n    });\n}\n\n// macOS notification with sound\nelse if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n{\n    Electron.Notification.Show(new NotificationOptions\n    {\n        Title = \"Alert\",\n        Body = \"Something needs your attention\",\n        Sound = NotificationSound.Default,\n        Actions = new[]\n        {\n            new NotificationAction { Text = \"View\", Type = NotificationActionType.Button }\n        }\n    });\n}\n```\n\n### Notification Management\n\n```csharp\n// Check notification support\nvar isSupported = await Electron.Notification.IsSupportedAsync();\nConsole.WriteLine($\"Notifications supported: {isSupported}\");\n\n// Create notification with events\nvar notification = new NotificationOptions\n{\n    Title = \"Task Complete\",\n    Body = \"Your long-running task has finished\",\n    OnShow = () => Console.WriteLine(\"Notification displayed\"),\n    OnClick = () => OpenTaskResults(),\n    OnClose = () => Console.WriteLine(\"Notification dismissed\")\n};\n\nElectron.Notification.Show(notification);\n```\n\n## Related APIs\n\n- [Electron.App](App.md) - Application lifecycle events\n- [Electron.Tray](Tray.md) - System tray integration with notifications\n- [Electron.Screen](Screen.md) - Position notifications based on screen layout\n\n## Additional Resources\n\n- [Electron Notification Documentation](https://electronjs.org/docs/api/notification) - Official Electron notification API\n"
  },
  {
    "path": "docs/API/Overview.md",
    "content": "# API Reference Overview\n\nThe ElectronNET.Core API provides comprehensive access to Electron's native desktop functionality through a .NET interface. This section documents all the available API classes and their methods, events, and usage patterns.\n\n## API Classes\n\n### Core Application Management\n- **[Electron.App](App.md)** - Control your application's event lifecycle, manage app metadata, and handle system-level operations\n- **[Electron.WindowManager](WindowManager.md)** - Create and manage browser windows, control window behavior and appearance\n- **[Electron.Menu](Menu.md)** - Create application menus, context menus, and menu items with full keyboard shortcut support\n\n### User Interface & Interaction\n- **[Electron.Dialog](Dialog.md)** - Display native system dialogs for opening/saving files, showing messages and alerts\n- **[Electron.Notification](Notification.md)** - Show native desktop notifications with custom content and actions\n- **[Electron.Tray](Tray.md)** - Create system tray icons with context menus and tooltip support\n- **[Electron.Dock](Dock.md)** - macOS dock integration for bounce effects and badge counts\n\n### System Integration\n- **[Electron.Shell](Shell.md)** - Desktop integration for opening files, URLs, and accessing system paths\n- **[Electron.Clipboard](Clipboard.md)** - Read from and write to the system clipboard with multiple data formats\n- **[Electron.Screen](Screen.md)** - Access display and screen information for responsive layouts\n- **[Electron.NativeTheme](NativeTheme.md)** - Detect and respond to system theme changes (light/dark mode)\n\n### Communication & Automation\n- **[Electron.IpcMain](IpcMain.md)** - Inter-process communication between main process and renderer processes\n- **[Electron.HostHook](HostHook.md)** - Custom host hook functionality for advanced integration scenarios\n- **[Electron.GlobalShortcut](GlobalShortcut.md)** - Register global keyboard shortcuts that work even when app is not focused\n- **[Electron.AutoUpdater](AutoUpdater.md)** - Handle application updates and installation processes\n\n### System Monitoring\n- **[Electron.PowerMonitor](PowerMonitor.md)** - Monitor system power events like sleep, wake, and battery status\n\n\n## API Relationships\n\n### Window and Dialog Integration\n- Use `BrowserWindow` instances as parent windows for dialogs\n- Dialogs automatically become modal when parent window is provided\n- Window events coordinate with application lifecycle events\n\n### IPC Communication\n- `IpcMain` handles communication from renderer processes\n- Use with `Electron.WindowManager` for window-specific messaging\n- Coordinate with `Electron.App` events for application-wide communication\n\n### System Integration\n- `Shell` operations work with file paths from `Dialog` operations\n- `Screen` information helps create properly sized windows\n- `Notification` and `Tray` provide complementary user interaction methods\n\n## 🚀 Next Steps\n\n- **[Electron.App](App.md)** - Start with application lifecycle management\n- **[Electron.WindowManager](WindowManager.md)** - Learn window creation and management\n- **[Electron.Dialog](Dialog.md)** - Add file operations and user interactions\n- **[Electron.Menu](Menu.md)** - Implement application menus and shortcuts\n\n## 📚 Additional Resources\n\n- **[Electron Documentation](https://electronjs.org/docs)** - Official Electron API reference\n- **[Getting Started](../GettingStarted/ASP.Net.md)** - Development setup guides\n- **[Migration Guide](../Core/Migration-Guide.md)** - Moving from previous versions\n"
  },
  {
    "path": "docs/API/PowerMonitor.md",
    "content": "# Electron.PowerMonitor\n\nMonitor system power events like sleep, wake, and battery status.\n\n## Overview\n\nThe `Electron.PowerMonitor` API provides access to system power events and state changes. This includes monitoring when the system is going to sleep, waking up, or changing power sources.\n\n## Events\n\n#### ⚡ `OnAC`\nEmitted when the system changes to AC power.\n\n#### ⚡ `OnBattery`\nEmitted when system changes to battery power.\n\n#### ⚡ `OnLockScreen`\nEmitted when the system is about to lock the screen.\n\n#### ⚡ `OnResume`\nEmitted when system is resuming.\n\n#### ⚡ `OnShutdown`\nEmitted when the system is about to reboot or shut down.\n\n#### ⚡ `OnSuspend`\nEmitted when the system is suspending.\n\n#### ⚡ `OnUnLockScreen`\nEmitted when the system is about to unlock the screen.\n\n## Usage Examples\n\n### Basic Power Event Monitoring\n\n```csharp\n// Monitor system sleep/wake\nElectron.PowerMonitor.OnSuspend += () =>\n{\n    Console.WriteLine(\"System going to sleep\");\n    // Save application state\n    SaveApplicationState();\n};\n\nElectron.PowerMonitor.OnResume += () =>\n{\n    Console.WriteLine(\"System waking up\");\n    // Restore application state\n    RestoreApplicationState();\n};\n```\n\n### Screen Lock/Unlock Monitoring\n\n```csharp\n// Handle screen lock events\nElectron.PowerMonitor.OnLockScreen += () =>\n{\n    Console.WriteLine(\"Screen locking\");\n    // Pause real-time operations\n    PauseRealTimeOperations();\n};\n\nElectron.PowerMonitor.OnUnLockScreen += () =>\n{\n    Console.WriteLine(\"Screen unlocking\");\n    // Resume real-time operations\n    ResumeRealTimeOperations();\n};\n```\n\n### Power Source Changes\n\n```csharp\n// Monitor power source changes\nElectron.PowerMonitor.OnAC += () =>\n{\n    Console.WriteLine(\"Switched to AC power\");\n    // Adjust power-intensive operations\n    EnablePowerIntensiveFeatures();\n};\n\nElectron.PowerMonitor.OnBattery += () =>\n{\n    Console.WriteLine(\"Switched to battery power\");\n    // Reduce power consumption\n    EnablePowerSavingMode();\n};\n```\n\n### System Shutdown Handling\n\n```csharp\n// Handle system shutdown\nElectron.PowerMonitor.OnShutdown += () =>\n{\n    Console.WriteLine(\"System shutting down\");\n    // Save critical data and exit gracefully\n    SaveAndExit();\n};\n```\n\n### Application State Management\n\n```csharp\nprivate bool isSuspended = false;\n\npublic void InitializePowerMonitoring()\n{\n    // Track suspension state\n    Electron.PowerMonitor.OnSuspend += () =>\n    {\n        isSuspended = true;\n        OnSystemSleep();\n    };\n\n    Electron.PowerMonitor.OnResume += () =>\n    {\n        isSuspended = false;\n        OnSystemWake();\n    };\n\n    // Handle screen lock for security\n    Electron.PowerMonitor.OnLockScreen += () =>\n    {\n        OnScreenLocked();\n    };\n}\n\nprivate void OnSystemSleep()\n{\n    // Pause network operations\n    PauseNetworkOperations();\n\n    // Save unsaved work\n    AutoSaveDocuments();\n\n    // Reduce resource usage\n    MinimizeResourceUsage();\n}\n\nprivate void OnSystemWake()\n{\n    // Resume network operations\n    ResumeNetworkOperations();\n\n    // Check for updates\n    CheckForUpdates();\n\n    // Restore full functionality\n    RestoreFullFunctionality();\n}\n\nprivate void OnScreenLocked()\n{\n    // Hide sensitive information\n    HideSensitiveData();\n\n    // Pause real-time features\n    PauseRealTimeFeatures();\n}\n```\n\n### Battery Status Monitoring\n\n```csharp\n// Monitor battery status changes\nElectron.PowerMonitor.OnAC += () =>\n{\n    Console.WriteLine(\"Plugged in - full performance mode\");\n    EnableFullPerformanceMode();\n};\n\nElectron.PowerMonitor.OnBattery += () =>\n{\n    Console.WriteLine(\"On battery - power saving mode\");\n    EnablePowerSavingMode();\n};\n```\n\n## Related APIs\n\n- [Electron.App](App.md) - Application lifecycle events\n- [Electron.Notification](Notification.md) - Notify users about power events\n\n## Additional Resources\n\n- [Electron PowerMonitor Documentation](https://electronjs.org/docs/api/power-monitor) - Official Electron power monitor API\n"
  },
  {
    "path": "docs/API/Screen.md",
    "content": "# Electron.Screen\n\nAccess display and screen information for responsive layouts.\n\n## Overview\n\nThe `Electron.Screen` API provides access to screen and display information, including screen size, display metrics, cursor position, and multi-monitor configurations. This is essential for creating responsive applications that adapt to different screen configurations.\n\n## Methods\n\n#### 🧊 `Task<Display[]> GetAllDisplaysAsync()`\nGets information about all available displays.\n\n**Returns:**\n\nAn array of displays that are currently available.\n\n#### 🧊 `Task<Point> GetCursorScreenPointAsync()`\nGets the current position of the mouse cursor on screen.\n\n**Returns:**\n\nThe current absolute position of the mouse pointer.\n\n#### 🧊 `Task<Display> GetDisplayMatchingAsync(Rectangle rectangle)`\nGets the display that most closely intersects the provided bounds.\n\n**Parameters:**\n- `rectangle` - The rectangle to find the matching display for\n\n**Returns:**\n\nThe display that most closely intersects the provided bounds.\n\n#### 🧊 `Task<Display> GetDisplayNearestPointAsync(Point point)`\nGets the display that is closest to the specified point.\n\n**Parameters:**\n- `point` - The point to find the nearest display for\n\n**Returns:**\n\nThe display nearest the specified point.\n\n#### 🧊 `Task<int> GetMenuBarHeightAsync()`\nmacOS: The height of the menu bar in pixels.\n\n**Returns:**\n\nThe height of the menu bar in pixels.\n\n#### 🧊 `Task<Display> GetPrimaryDisplayAsync()`\nGets information about the primary display (main screen).\n\n**Returns:**\n\nThe primary display.\n\n## Events\n\n#### ⚡ `OnDisplayAdded`\nEmitted when a new Display has been added.\n\n#### ⚡ `OnDisplayMetricsChanged`\nEmitted when one or more metrics change in a display. The changedMetrics is an array of strings that describe the changes. Possible changes are bounds, workArea, scaleFactor and rotation.\n\n#### ⚡ `OnDisplayRemoved`\nEmitted when oldDisplay has been removed.\n\n## Usage Examples\n\n### Display Information\n\n```csharp\n// Get primary display\nvar primaryDisplay = await Electron.Screen.GetPrimaryDisplayAsync();\nConsole.WriteLine($\"Primary display: {primaryDisplay.Size.Width}x{primaryDisplay.Size.Height}\");\n\n// Get all displays\nvar displays = await Electron.Screen.GetAllDisplaysAsync();\nConsole.WriteLine($\"Available displays: {displays.Length}\");\n\n// Get display near cursor\nvar cursorPoint = await Electron.Screen.GetCursorScreenPointAsync();\nvar nearestDisplay = await Electron.Screen.GetDisplayNearestPointAsync(cursorPoint);\nConsole.WriteLine($\"Nearest display scale factor: {nearestDisplay.ScaleFactor}\");\n```\n\n### Multi-Monitor Setup\n\n```csharp\n// Get all displays for multi-monitor setup\nvar displays = await Electron.Screen.GetAllDisplaysAsync();\n\nforeach (var display in displays)\n{\n    Console.WriteLine($\"Display {display.Id}:\");\n    Console.WriteLine($\"  Size: {display.Size.Width}x{display.Size.Height}\");\n    Console.WriteLine($\"  Position: {display.Bounds.X},{display.Bounds.Y}\");\n    Console.WriteLine($\"  Scale Factor: {display.ScaleFactor}\");\n    Console.WriteLine($\"  Work Area: {display.WorkArea.Width}x{display.WorkArea.Height}\");\n}\n```\n\n### Responsive Window Placement\n\n```csharp\n// Create window on appropriate display\nvar displays = await Electron.Screen.GetAllDisplaysAsync();\nvar targetDisplay = displays.FirstOrDefault(d => d.Bounds.X > 0) ?? displays.First();\n\nvar windowOptions = new BrowserWindowOptions\n{\n    Width = Math.Min(1200, targetDisplay.WorkArea.Width),\n    Height = Math.Min(800, targetDisplay.WorkArea.Height),\n    X = targetDisplay.WorkArea.X + (targetDisplay.WorkArea.Width - 1200) / 2,\n    Y = targetDisplay.WorkArea.Y + (targetDisplay.WorkArea.Height - 800) / 2\n};\n\nvar window = await Electron.WindowManager.CreateWindowAsync(windowOptions);\n```\n\n### Display Change Monitoring\n\n```csharp\n// Monitor display changes\nElectron.Screen.OnDisplayAdded += (display) =>\n{\n    Console.WriteLine($\"Display added: {display.Id}\");\n    UpdateWindowPositions();\n};\n\nElectron.Screen.OnDisplayRemoved += (display) =>\n{\n    Console.WriteLine($\"Display removed: {display.Id}\");\n    UpdateWindowPositions();\n};\n\nElectron.Screen.OnDisplayMetricsChanged += (display, metrics) =>\n{\n    Console.WriteLine($\"Display {display.Id} metrics changed: {string.Join(\", \", metrics)}\");\n    UpdateWindowPositions();\n};\n\nvoid UpdateWindowPositions()\n{\n    // Recalculate window positions based on current displays\n}\n```\n\n### macOS Menu Bar Height\n\n```csharp\n// Account for menu bar height on macOS\nif (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n{\n    var menuBarHeight = await Electron.Screen.GetMenuBarHeightAsync();\n\n    var windowOptions = new BrowserWindowOptions\n    {\n        Y = menuBarHeight, // Position below menu bar\n        TitleBarStyle = TitleBarStyle.Hidden // Hide title bar for custom look\n    };\n}\n```\n\n## Related APIs\n\n- [Electron.WindowManager](WindowManager.md) - Position windows based on screen information\n- [Electron.App](App.md) - Handle display-related application events\n\n## Additional Resources\n\n- [Electron Screen Documentation](https://electronjs.org/docs/api/screen) - Official Electron screen API\n"
  },
  {
    "path": "docs/API/Shell.md",
    "content": "# Electron.Shell\n\nDesktop integration for opening files, URLs, and accessing system paths.\n\n## Overview\n\nThe `Electron.Shell` API provides system integration functionality for opening files and URLs with their default applications, managing trash/recycle bin, and creating/reading shortcut links.\n\n## Methods\n\n#### 🧊 `void Beep()`\nPlay the beep sound.\n\n#### 🧊 `Task<string> OpenExternalAsync(string url)`\nOpen the given external protocol URL in the desktop's default manner (e.g., mailto: URLs in the user's default mail agent).\n\n**Parameters:**\n- `url` - Max 2081 characters on windows\n\n**Returns:**\n\nThe error message corresponding to the failure if a failure occurred, otherwise empty string.\n\n#### 🧊 `Task<string> OpenExternalAsync(string url, OpenExternalOptions options)`\nOpen the given external protocol URL with additional options.\n\n**Parameters:**\n- `url` - Max 2081 characters on windows\n- `options` - Controls the behavior of OpenExternal\n\n**Returns:**\n\nThe error message corresponding to the failure if a failure occurred, otherwise empty string.\n\n#### 🧊 `Task<string> OpenPathAsync(string path)`\nOpen the given file in the desktop's default manner.\n\n**Parameters:**\n- `path` - The path to the directory or file\n\n**Returns:**\n\nThe error message corresponding to the failure if a failure occurred, otherwise empty string.\n\n#### 🧊 `Task<ShortcutDetails> ReadShortcutLinkAsync(string shortcutPath)`\nResolves the shortcut link at shortcutPath. An exception will be thrown when any error happens.\n\n**Parameters:**\n- `shortcutPath` - The path to the shortcut\n\n**Returns:**\n\nShortcutDetails of the shortcut.\n\n#### 🧊 `Task ShowItemInFolderAsync(string fullPath)`\nShow the given file in a file manager. If possible, select the file.\n\n**Parameters:**\n- `fullPath` - The full path to the directory or file\n\n#### 🧊 `Task<bool> TrashItemAsync(string fullPath)`\nMove the given file to trash and returns a bool status for the operation.\n\n**Parameters:**\n- `fullPath` - The full path to the directory or file\n\n**Returns:**\n\nWhether the item was successfully moved to the trash.\n\n#### 🧊 `Task<bool> WriteShortcutLinkAsync(string shortcutPath, ShortcutLinkOperation operation, ShortcutDetails options)`\nCreates or updates a shortcut link at shortcutPath.\n\n**Parameters:**\n- `shortcutPath` - The path to the shortcut\n- `operation` - Default is ShortcutLinkOperation.Create\n- `options` - Structure of a shortcut\n\n**Returns:**\n\nWhether the shortcut was created successfully.\n\n## Usage Examples\n\n### File Operations\n\n```csharp\n// Open file with default application\nvar error = await Electron.Shell.OpenPathAsync(filePath);\nif (string.IsNullOrEmpty(error))\n{\n    Console.WriteLine(\"File opened successfully\");\n}\nelse\n{\n    Console.WriteLine($\"Failed to open file: {error}\");\n}\n\n// Show file in file manager\nawait Electron.Shell.ShowItemInFolderAsync(filePath);\n\n// Move file to trash\nvar trashed = await Electron.Shell.TrashItemAsync(filePath);\nConsole.WriteLine($\"File trashed: {trashed}\");\n```\n\n### URL Operations\n\n```csharp\n// Open URL in default browser\nvar error = await Electron.Shell.OpenExternalAsync(\"https://electron.net\");\nif (!string.IsNullOrEmpty(error))\n{\n    Console.WriteLine($\"Failed to open URL: {error}\");\n}\n\n// Open email client\nawait Electron.Shell.OpenExternalAsync(\"mailto:user@example.com\");\n\n// Open with options\nvar error = await Electron.Shell.OpenExternalAsync(\"https://example.com\", new OpenExternalOptions\n{\n    Activate = true\n});\n```\n\n### System Integration\n\n```csharp\n// Play system beep\nElectron.Shell.Beep();\n\n// Create desktop shortcut\nvar success = await Electron.Shell.WriteShortcutLinkAsync(\n    @\"C:\\Users\\Public\\Desktop\\MyApp.lnk\",\n    ShortcutLinkOperation.Create,\n    new ShortcutDetails\n    {\n        Target = \"C:\\\\Program Files\\\\MyApp\\\\MyApp.exe\",\n        Description = \"My Application\",\n        WorkingDirectory = \"C:\\\\Program Files\\\\MyApp\"\n    }\n);\n\n// Read shortcut information\nvar details = await Electron.Shell.ReadShortcutLinkAsync(@\"C:\\Users\\Public\\Desktop\\MyApp.lnk\");\nConsole.WriteLine($\"Target: {details.Target}\");\n```\n\n### Integration with Dialog API\n\n```csharp\n// Use with file dialog results\nvar files = await Electron.Dialog.ShowOpenDialogAsync(window, options);\nif (files.Length > 0)\n{\n    var selectedFile = files[0];\n\n    // Open the selected file\n    await Electron.Shell.OpenPathAsync(selectedFile);\n\n    // Show in file manager\n    await Electron.Shell.ShowItemInFolderAsync(selectedFile);\n}\n```\n\n## Related APIs\n\n- [Electron.Dialog](Dialog.md) - Select files to open with Shell\n- [Electron.App](App.md) - Application lifecycle events\n- [Electron.Clipboard](Clipboard.md) - Copy file paths for Shell operations\n\n## Additional Resources\n\n- [Electron Shell Documentation](https://electronjs.org/docs/api/shell) - Official Electron shell API\n"
  },
  {
    "path": "docs/API/Tray.md",
    "content": "# Electron.Tray\n\nAdd icons and context menus to the system's notification area.\n\n## Overview\n\nThe `Electron.Tray` API provides the ability to add icons and context menus to the system's notification area (system tray). This allows applications to provide quick access to common functions and maintain a presence in the system even when windows are closed.\n\n## Properties\n\n#### 📋 `IReadOnlyCollection<MenuItem> MenuItems`\nGets a read-only collection of all current tray menu items.\n\n## Methods\n\n#### 🧊 `void Destroy()`\nDestroys the tray icon immediately.\n\n#### 🧊 `void DisplayBalloon(DisplayBalloonOptions options)`\nWindows: Displays a tray balloon notification.\n\n**Parameters:**\n- `options` - Balloon notification options\n\n#### 🧊 `Task<bool> IsDestroyedAsync()`\nCheck if the tray icon has been destroyed.\n\n**Returns:**\n\nWhether the tray icon is destroyed.\n\n#### 🧊 `void SetImage(string image)`\nSets the image associated with this tray icon.\n\n**Parameters:**\n- `image` - New image for the tray icon\n\n#### 🧊 `void SetPressedImage(string image)`\nSets the image associated with this tray icon when pressed on macOS.\n\n**Parameters:**\n- `image` - Image for pressed state\n\n#### 🧊 `void SetTitle(string title)`\nmacOS: Sets the title displayed aside of the tray icon in the status bar.\n\n**Parameters:**\n- `title` - Title text\n\n#### 🧊 `void SetToolTip(string toolTip)`\nSets the hover text for this tray icon.\n\n**Parameters:**\n- `toolTip` - Tooltip text\n\n#### 🧊 `void Show(string image)`\nShows the tray icon without a context menu.\n\n**Parameters:**\n- `image` - The image to use for the tray icon\n\n#### 🧊 `void Show(string image, MenuItem menuItem)`\nShows the tray icon with a single menu item.\n\n**Parameters:**\n- `image` - The image to use for the tray icon\n- `menuItem` - Single menu item for the tray context menu\n\n#### 🧊 `void Show(string image, MenuItem[] menuItems)`\nShows the tray icon with multiple menu items.\n\n**Parameters:**\n- `image` - The image to use for the tray icon\n- `menuItems` - Array of menu items for the tray context menu\n\n## Events\n\n#### ⚡ `OnBalloonClick`\nWindows: Emitted when the tray balloon is clicked.\n\n#### ⚡ `OnBalloonClosed`\nWindows: Emitted when the tray balloon is closed because of timeout or user manually closes it.\n\n#### ⚡ `OnBalloonShow`\nWindows: Emitted when the tray balloon shows.\n\n#### ⚡ `OnClick`\nEmitted when the tray icon is clicked.\n\n#### ⚡ `OnDoubleClick`\nmacOS, Windows: Emitted when the tray icon is double clicked.\n\n#### ⚡ `OnRightClick`\nmacOS, Windows: Emitted when the tray icon is right clicked.\n\n## Usage Examples\n\n### Basic Tray Icon\n\n```csharp\n// Simple tray icon\nawait Electron.Tray.Show(\"assets/tray-icon.png\");\n\n// Tray icon with single menu item\nawait Electron.Tray.Show(\"assets/tray-icon.png\", new MenuItem\n{\n    Label = \"Show Window\",\n    Click = () => ShowMainWindow()\n});\n```\n\n### Tray with Context Menu\n\n```csharp\n// Tray with multiple menu items\nvar trayMenuItems = new[]\n{\n    new MenuItem { Label = \"Show Window\", Click = () => ShowMainWindow() },\n    new MenuItem { Label = \"Settings\", Click = () => OpenSettings() },\n    new MenuItem { Type = MenuType.Separator },\n    new MenuItem { Label = \"Exit\", Click = () => Electron.App.Quit() }\n};\n\nawait Electron.Tray.Show(\"assets/tray-icon.png\", trayMenuItems);\n```\n\n### Dynamic Tray Updates\n\n```csharp\n// Update tray tooltip based on status\nawait Electron.Tray.SetToolTip(\"MyApp - Connected\");\n\n// Change tray icon based on state\nif (isConnected)\n{\n    await Electron.Tray.SetImage(\"assets/connected.png\");\n}\nelse\n{\n    await Electron.Tray.SetImage(\"assets/disconnected.png\");\n}\n```\n\n### Tray Event Handling\n\n```csharp\n// Handle tray clicks\nElectron.Tray.OnClick += (clickArgs, bounds) =>\n{\n    if (clickArgs.AltKey || clickArgs.ShiftKey)\n    {\n        // Alt+Click or Shift+Click - show context menu\n        Electron.Menu.ContextMenuPopup(Electron.WindowManager.BrowserWindows.First());\n    }\n    else\n    {\n        // Regular click - toggle main window\n        ToggleMainWindow();\n    }\n};\n\nElectron.Tray.OnRightClick += (clickArgs, bounds) =>\n{\n    // Show context menu on right click\n    Electron.Menu.ContextMenuPopup(Electron.WindowManager.BrowserWindows.First());\n};\n```\n\n### Windows Balloon Notifications\n\n```csharp\n// Show Windows balloon notification\nawait Electron.Tray.DisplayBalloon(new DisplayBalloonOptions\n{\n    Title = \"Background Task Complete\",\n    Content = \"Your file has been processed successfully.\",\n    Icon = \"assets/notification-icon.ico\"\n});\n\n// Handle balloon events\nElectron.Tray.OnBalloonClick += () =>\n{\n    ShowMainWindow();\n    Electron.WindowManager.BrowserWindows.First().Focus();\n};\n```\n\n### macOS Tray Features\n\n```csharp\n// macOS specific tray features\nif (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n{\n    await Electron.Tray.SetTitle(\"MyApp\");\n\n    // Use template image for dark mode support\n    await Electron.Tray.SetImage(\"assets/tray-template.png\");\n    await Electron.Tray.SetPressedImage(\"assets/tray-pressed-template.png\");\n}\n```\n\n### Application Integration\n\n```csharp\n// Integrate with application lifecycle\nElectron.App.WindowAllClosed += () =>\n{\n    // Keep app running in tray when windows are closed\n    if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n    {\n        Electron.App.Hide();\n    }\n};\n\n// Handle tray double-click\nElectron.Tray.OnDoubleClick += (clickArgs, bounds) =>\n{\n    ShowMainWindow();\n    Electron.WindowManager.BrowserWindows.First().Focus();\n};\n```\n\n## Related APIs\n\n- [Electron.Menu](Menu.md) - Context menus for tray icons\n- [Electron.Notification](Notification.md) - Desktop notifications\n- [Electron.App](App.md) - Application lifecycle events\n- [Electron.WindowManager](WindowManager.md) - Windows to show/hide from tray\n\n## Additional Resources\n\n- [Electron Tray Documentation](https://electronjs.org/docs/api/tray) - Official Electron tray API\n"
  },
  {
    "path": "docs/API/WebContents.md",
    "content": "# Electron.WebContents\n\nRender and control web pages.\n\n## Overview\n\nThe `Electron.WebContents` API provides control over web page content within Electron windows. It handles page loading, navigation, JavaScript execution, and web page lifecycle events.\n\n## Properties\n\n#### 📋 `int Id`\nGets the unique identifier for this web contents.\n\n#### 📋 `Session Session`\nManage browser sessions, cookies, cache, proxy settings, etc.\n\n## Methods\n\n#### 🧊 `void ExecuteJavaScriptAsync(string code, bool userGesture = false)`\nEvaluates script code in page.\n\nIn the browser window some HTML APIs like `requestFullScreen` can only be invoked by a gesture from the user. Setting `userGesture` to `true` will remove this limitation.\n\nCode execution will be suspended until web page stop loading.\n\n**Parameters:**\n- `code` - The code to execute\n- `userGesture` - if set to `true` simulate a user gesture\n\n**Returns:**\n\nThe result of the executed code.\n\n#### 🧊 `Task<PrinterInfo[]> GetPrintersAsync()`\nGet system printers.\n\n**Returns:**\n\nArray of available printers.\n\n#### 🧊 `Task<string> GetUrl()`\nGet the URL of the loaded page.\n\nIt's useful if a web-server redirects you and you need to know where it redirects. For instance, It's useful in case of Implicit Authorization.\n\n**Returns:**\n\nURL of the loaded page.\n\n#### 🧊 `void InsertCSS(bool isBrowserWindow, string path)`\nInserts CSS into the web page.\n\nSee: https://www.electronjs.org/docs/api/web-contents#contentsinsertcsscss-options\n\nWorks for both BrowserWindows and BrowserViews.\n\n**Parameters:**\n- `isBrowserWindow` - Whether the webContents belong to a BrowserWindow or not (the other option is a BrowserView)\n- `path` - Absolute path to the CSS file location\n\n#### 🧊 `Task LoadURLAsync(string url)`\nLoads the url in the window. The url must contain the protocol prefix.\n\nThe async method will resolve when the page has finished loading, and rejects if the page fails to load.\n\nA noop rejection handler is already attached, which avoids unhandled rejection errors.\n\nLoads the `url` in the window. The `url` must contain the protocol prefix, e.g. the `http://` or `file://`. If the load should bypass http cache then use the `pragma` header to achieve it.\n\n**Parameters:**\n- `url` - URL to load\n\n#### 🧊 `Task LoadURLAsync(string url, LoadURLOptions options)`\nLoads the url with additional options.\n\nThe async method will resolve when the page has finished loading, and rejects if the page fails to load.\n\nA noop rejection handler is already attached, which avoids unhandled rejection errors.\n\nLoads the `url` in the window. The `url` must contain the protocol prefix, e.g. the `http://` or `file://`. If the load should bypass http cache then use the `pragma` header to achieve it.\n\n**Parameters:**\n- `url` - URL to load\n- `options` - Loading options\n\n#### 🧊 `void OpenDevTools()`\nOpens the devtools.\n\n#### 🧊 `void OpenDevTools(OpenDevToolsOptions openDevToolsOptions)`\nOpens the devtools with options.\n\n**Parameters:**\n- `openDevToolsOptions` - Developer tools options\n\n#### 🧊 `Task<bool> PrintAsync(PrintOptions options = null)`\nPrints window's web page.\n\n**Parameters:**\n- `options` - Print options\n\n**Returns:**\n\nWhether the print operation succeeded.\n\n#### 🧊 `Task<bool> PrintToPDFAsync(string path, PrintToPDFOptions options = null)`\nPrints window's web page as PDF with Chromium's preview printing custom settings.The landscape will be ignored if @page CSS at-rule is used in the web page. By default, an empty options will be regarded as: Use page-break-before: always; CSS style to force to print to a new page.\n\n**Parameters:**\n- `path` - Output file path\n- `options` - PDF generation options\n\n**Returns:**\n\nWhether the PDF generation succeeded.\n\n## Events\n\n#### ⚡ `InputEvent`\nEmitted when an input event is sent to the WebContents.\n\n#### ⚡ `OnCrashed`\nEmitted when the renderer process crashes or is killed.\n\n#### ⚡ `OnDidFailLoad`\nEmitted when the load failed.\n\n#### ⚡ `OnDidFinishLoad`\nEmitted when the navigation is done, i.e. the spinner of the tab has stopped spinning, and the onload event was dispatched.\n\n#### ⚡ `OnDidNavigate`\nEmitted when a main frame navigation is done.\n\n#### ⚡ `OnDidRedirectNavigation`\nEmitted after a server side redirect occurs during navigation.\n\n#### ⚡ `OnDidStartNavigation`\nEmitted when any frame (including main) starts navigating.\n\n#### ⚡ `OnDomReady`\nEmitted when the document in the top-level frame is loaded.\n\n#### ⚡ `OnWillRedirect`\nEmitted when a server side redirect occurs during navigation.\n\n## Usage Examples\n\n### Page Loading\n\n```csharp\n// Load URL with options\nawait webContents.LoadURLAsync(\"https://example.com\", new LoadURLOptions\n{\n    UserAgent = \"MyApp/1.0\",\n    ExtraHeaders = \"Authorization: Bearer token123\"\n});\n\n// Load local file\nawait webContents.LoadURLAsync(\"file://\" + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, \"app/index.html\"));\n\n// Get current URL\nvar currentUrl = await webContents.GetUrl();\nConsole.WriteLine($\"Current URL: {currentUrl}\");\n```\n\n### JavaScript Execution\n\n```csharp\n// Execute simple JavaScript\nvar result = await webContents.ExecuteJavaScriptAsync(\"document.title\");\nConsole.WriteLine($\"Page title: {result}\");\n\n// Execute with user gesture simulation\nawait webContents.ExecuteJavaScriptAsync(\"document.requestFullscreen()\", true);\n\n// Execute complex code\nvar userAgent = await webContents.ExecuteJavaScriptAsync(\"navigator.userAgent\");\nConsole.WriteLine($\"User agent: {userAgent}\");\n```\n\n### Developer Tools\n\n```csharp\n// Open dev tools\nwebContents.OpenDevTools();\n\n// Open with specific options\nwebContents.OpenDevTools(new OpenDevToolsOptions\n{\n    Mode = DevToolsMode.Detached,\n    Activate = true\n});\n```\n\n### CSS Injection\n\n```csharp\n// Inject CSS file\nwebContents.InsertCSS(true, \"styles/custom-theme.css\");\n\n// Inject CSS for BrowserView\nwebContents.InsertCSS(false, \"styles/browser-view.css\");\n```\n\n### Printing Operations\n\n```csharp\n// Print web page\nvar printSuccess = await webContents.PrintAsync(new PrintOptions\n{\n    Silent = false,\n    PrintBackground = true,\n    DeviceName = \"My Printer\"\n});\n\nif (printSuccess)\n{\n    Console.WriteLine(\"Print job sent successfully\");\n}\n```\n\n### PDF Generation\n\n```csharp\n// Generate PDF\nvar pdfSuccess = await webContents.PrintToPDFAsync(\"document.pdf\", new PrintToPDFOptions\n{\n    MarginsType = PrintToPDFMarginsType.None,\n    PageSize = PrintToPDFPageSize.A4,\n    PrintBackground = true,\n    Landscape = false\n});\n\nif (pdfSuccess)\n{\n    Console.WriteLine(\"PDF generated successfully\");\n}\n```\n\n### Navigation Monitoring\n\n```csharp\n// Monitor navigation events\nwebContents.OnDidStartNavigation += (url) =>\n{\n    Console.WriteLine($\"Starting navigation to: {url}\");\n};\n\nwebContents.OnDidNavigate += (navInfo) =>\n{\n    Console.WriteLine($\"Navigated to: {navInfo.Url}\");\n};\n\nwebContents.OnDidFinishLoad += () =>\n{\n    Console.WriteLine(\"Page finished loading\");\n};\n\nwebContents.OnDidFailLoad += (failInfo) =>\n{\n    Console.WriteLine($\"Page failed to load: {failInfo.ErrorCode} - {failInfo.ErrorDescription}\");\n};\n```\n\n### Content Interaction\n\n```csharp\n// Wait for DOM ready\nwebContents.OnDomReady += () =>\n{\n    Console.WriteLine(\"DOM is ready\");\n    // Safe to execute DOM-related JavaScript now\n};\n\n// Handle page crashes\nwebContents.OnCrashed += (killed) =>\n{\n    Console.WriteLine($\"Renderer crashed, killed: {killed}\");\n    // Optionally reload the page\n};\n```\n\n## Related APIs\n\n- [Electron.WindowManager](WindowManager.md) - Windows containing web contents\n- [Electron.Session](Session.md) - Session management for web contents\n- [Electron.IpcMain](IpcMain.md) - Communication with web contents\n\n## Additional Resources\n\n- [Electron WebContents Documentation](https://electronjs.org/docs/api/web-contents) - Official Electron web contents API\n- [Web Content Management](../Core/What's-New.md) - Understanding web content handling\n- [Security Considerations](../Using/Configuration.md) - Secure web content integration\n"
  },
  {
    "path": "docs/API/WindowManager.md",
    "content": "# Electron.WindowManager\n\nCreate and manage browser windows, control window behavior and appearance.\n\n## Overview\n\nThe `Electron.WindowManager` API provides comprehensive control over browser windows in your Electron application. It handles window creation, management, and coordination with the application lifecycle.\n\n## Properties\n\n#### 📋 `IReadOnlyCollection<BrowserView> BrowserViews`\nGets a read-only collection of all currently open browser views.\n\n#### 📋 `IReadOnlyCollection<BrowserWindow> BrowserWindows`\nGets a read-only collection of all currently open browser windows.\n\n#### 📋 `bool IsQuitOnWindowAllClosed`\nControls whether the application quits when all windows are closed. Default is true.\n\n## Methods\n\n#### 🧊 `Task<BrowserView> CreateBrowserViewAsync()`\nCreates a new browser view with default options.\n\n**Returns:**\n\nThe created BrowserView instance.\n\n#### 🧊 `Task<BrowserView> CreateBrowserViewAsync(BrowserViewConstructorOptions options)`\nCreates a new browser view with custom options.\n\n**Parameters:**\n- `options` - Browser view configuration options\n\n**Returns:**\n\nThe created BrowserView instance.\n\n#### 🧊 `Task<BrowserWindow> CreateWindowAsync(string loadUrl = \"http://localhost\")`\nCreates a new browser window with default options.\n\n**Parameters:**\n- `loadUrl` - URL to load in the window. Defaults to \"http://localhost\"\n\n**Returns:**\n\nThe created BrowserWindow instance.\n\n#### 🧊 `Task<BrowserWindow> CreateWindowAsync(BrowserWindowOptions options, string loadUrl = \"http://localhost\")`\nCreates a new browser window with custom options.\n\n**Parameters:**\n- `options` - Window configuration options\n- `loadUrl` - URL to load in the window. Defaults to \"http://localhost\"\n\n**Returns:**\n\nThe created BrowserWindow instance.\n\n## Usage Examples\n\n### Basic Window Creation\n\n```csharp\n// Create window with default options\nvar mainWindow = await Electron.WindowManager.CreateWindowAsync();\n\n// Create window with custom options\nvar settingsWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions\n{\n    Width = 800,\n    Height = 600,\n    Show = false,\n    Title = \"Settings\",\n    WebPreferences = new WebPreferences\n    {\n        NodeIntegration = false,\n        ContextIsolation = true\n    }\n}, \"https://localhost:5001/settings\");\n```\n\n### Window Management\n\n```csharp\n// Get all windows\nvar windows = Electron.WindowManager.BrowserWindows;\nConsole.WriteLine($\"Open windows: {windows.Count}\");\n\n// Configure quit behavior\nElectron.WindowManager.IsQuitOnWindowAllClosed = false; // Keep app running when windows close\n\n// Handle window lifecycle\nElectron.App.WindowAllClosed += () =>\n{\n    Console.WriteLine(\"All windows closed\");\n    if (Electron.WindowManager.IsQuitOnWindowAllClosed)\n    {\n        Electron.App.Quit();\n    }\n};\n```\n\n### Browser View Integration\n\n```csharp\n// Create browser view\nvar browserView = await Electron.WindowManager.CreateBrowserViewAsync(new BrowserViewConstructorOptions\n{\n    WebPreferences = new WebPreferences\n    {\n        NodeIntegration = false,\n        ContextIsolation = true\n    }\n});\n\n// Add to window\nawait mainWindow.SetBrowserViewAsync(browserView);\nawait browserView.WebContents.LoadURLAsync(\"https://example.com\");\n\n// Set view bounds\nawait mainWindow.SetBoundsAsync(browserView, new Rectangle\n{\n    X = 0,\n    Y = 100,\n    Width = 800,\n    Height = 400\n});\n```\n\n### Window Options Configuration\n\n```csharp\n// Comprehensive window options\nvar options = new BrowserWindowOptions\n{\n    Width = 1200,\n    Height = 800,\n    MinWidth = 600,\n    MinHeight = 400,\n    MaxWidth = 1920,\n    MaxHeight = 1080,\n    X = 100,\n    Y = 100,\n    Center = true,\n    Frame = true,\n    Title = \"My Application\",\n    Icon = \"assets/app-icon.png\",\n    Show = false,\n    AlwaysOnTop = false,\n    SkipTaskbar = false,\n    Kiosk = false,\n    TitleBarStyle = TitleBarStyle.Default,\n    BackgroundColor = \"#FFFFFF\",\n    DarkTheme = false,\n    Transparent = false,\n    WebPreferences = new WebPreferences\n    {\n        NodeIntegration = false,\n        ContextIsolation = true,\n        EnableWebSQL = false,\n        Partition = \"persist:electron\",\n        ZoomFactor = 1.0f,\n        DevTools = true\n    }\n};\n```\n\n### Multi-Window Applications\n\n```csharp\n// Create main window\nvar mainWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions\n{\n    Width = 1200,\n    Height = 800,\n    Show = false\n});\n\n// Create secondary window\nvar secondaryWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions\n{\n    Width = 600,\n    Height = 400,\n    Parent = mainWindow,\n    Modal = true,\n    Show = false\n});\n\n// Load different content\nawait mainWindow.WebContents.LoadURLAsync(\"https://localhost:5001\");\nawait secondaryWindow.WebContents.LoadURLAsync(\"https://localhost:5001/settings\");\n\n// Show windows when ready\nmainWindow.OnReadyToShow += () => mainWindow.Show();\nsecondaryWindow.OnReadyToShow += () => secondaryWindow.Show();\n```\n\n## Related APIs\n\n- [Electron.App](App.md) - Application lifecycle and window events\n- [Electron.Dialog](Dialog.md) - Parent windows for modal dialogs\n- [Electron.Menu](Menu.md) - Window-specific menus\n- [Electron.WebContents](WebContents.md) - Window content management\n\n## Additional Resources\n\n- [Electron Window Management Documentation](https://electronjs.org/docs/api/browser-window) - Official Electron window API\n"
  },
  {
    "path": "docs/About.md",
    "content": "\n\n# About this Project\n\nElectron.NET has been developed by a small number of people in the hope that it may be useful for others.\n\nSupport for this project in all forms is very welcome, no matter whether in form of code contributions or donations.\n\n## 💬 Community\n\n[![Gitter](https://badges.gitter.im/ElectronNET/community.svg)](https://gitter.im/ElectronNET/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)\n\nBesides the chat on Gitter and the issues [discussed here](https://github.com/ElectronNET/Electron.NET/issues) you can also use [StackOverflow](https://stackoverflow.com/questions/tagged/electron.net) with the tag `electron.net`.\n\n\n## 🙋‍♀️🙋‍♂ Contributing\n\nFeel free to submit a pull request if you find any bugs (to see a list of active issues, visit the [Issues section](https://github.com/ElectronNET/Electron.NET/issues).\nPlease make sure all commits are properly documented.\n\n\n## 🙏 Donate\n\nWe do this open source work in our free time. If you'd like us to invest more time on it, please [donate](https://donorbox.org/electron-net). Donation can be used to increase some issue priority. Thank you!\n\n[![donate](https://img.shields.io/badge/Donate-Donorbox-green.svg)](https://donorbox.org/electron-net)\n\nAlternatively, consider using a GitHub sponsorship for the core maintainers:\n\n- [Gregor Biswanger](https://github.com/sponsors/GregorBiswanger)\n- [Florian Rappl](https://github.com/sponsors/FlorianRappl)\n\nAny support appreciated! 🍻\n\n\n## 👨‍💻 Authors\n\n* **[Gregor Biswanger](https://github.com/GregorBiswanger)** - (Microsoft MVP, Intel Black Belt and Intel Software Innovator) is a freelance lecturer, consultant, trainer, author and speaker. He is a consultant for large and medium-sized companies, organizations and agencies for software architecture, web- and cross-platform development. You can find Gregor often on the road attending or speaking at international conferences. - [Cross-Platform-Blog](http://www.cross-platform-blog.com) - Twitter [@BFreakout](https://www.twitter.com/BFreakout)  \n  &nbsp;  \n* **[Dr. Florian Rappl](https://github.com/FlorianRappl)** - Software Developer - from Munich, Germany. Microsoft MVP & Web Geek. - [The Art of Micro Frontends](https://microfrontends.art) - [Homepage](https://florian-rappl.de) - Twitter [@florianrappl](https://twitter.com/florianrappl)  \n  &nbsp;  \n* [**softworkz**](https://github.com/softworkz) - full range developer - likes to start where others gave up - MS MVP alumni and Munich citizen as well. Has not been involved in the evolution of Electron.NET but rather dropped off the update and overhaul for ElectronNET.Core in a kind-of drive-by action.  \n  &nbsp;  \n* **[Robert Muehsig](https://github.com/robertmuehsig)** - Software Developer - from Dresden, Germany, now living & working in Switzerland. Microsoft MVP & Web Geek. - [codeinside Blog](https://blog.codeinside.eu) - Twitter [@robert0muehsig](https://twitter.com/robert0muehsig)  \n  \nSee also the list of [contributors](https://github.com/ElectronNET/Electron.NET/graphs/contributors) who participated in this project.\n  \n\n## 🎉 License\n\nMIT-licensed. See [LICENSE](https://github.com/ElectronNET/Electron.NET?tab=MIT-1-ov-file#readme) for details.\n"
  },
  {
    "path": "docs/Core/Advanced-Migration-Topics.md",
    "content": "# Advanced Migration Topics\n\nThis guide covers advanced scenarios and edge cases that may require additional configuration when migrating to ElectronNET.Core.\n\n## Custom ASP.NET Port Configuration\n\n### Port Configuration Changes\n\n**Previous Approach:**  \nSpecifying the WebPort in `electron.manifest.json` is no longer supported because the ASP.NET-first launch mode makes this timing-dependent.\n\n**New Approach:**  \nConfigure custom ASP.NET ports through MSBuild metadata:\n\n```xml\n<ItemGroup>\n  <AssemblyMetadata Include=\"AspNetHttpPort\" Value=\"4000\" />\n</ItemGroup>\n```\n\n## Custom ElectronHostHook Configuration\n\n> [!NOTE]  \n> These changes are only required in case you are using a custom ElectronHostHook implementation!  \n> If you have an ElectronHostHook folder in your project but you did not customize that code and aren't using its demo features (Excel and ZIP), you can also just remove that folder from your project.\n\n\n### TypeScript and Node.js Updates\n\n**Update package.json:**\n\nThis shows the relevant changes only: All shown versions are the new required minimum versions.\n\n```json\n{\n  \"devDependencies\": {\n    \"@types/node\": \"^22.18\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"dependencies\": {\n    \"socket.io\": \"^4.8.1\",\n  }\n}\n```\n\n**Update Project File:**  \n\nThe below modifications will allow you to use the latest TypeScript compiler in your ASP.Net project.\n\n```xml\n<PackageReference Include=\"Microsoft.TypeScript.MSBuild\" Version=\"5.9.3\" />\n\n<PropertyGroup>\n  <TypeScriptModuleKind>commonjs</TypeScriptModuleKind>\n  <TypeScriptUseNodeJS>true</TypeScriptUseNodeJS>\n  <TypeScriptTSConfig>ElectronHostHook/tsconfig.json</TypeScriptTSConfig>\n</PropertyGroup>\n\n<ItemGroup>\n  <Compile Remove=\"publish\\**\" />\n  <Content Remove=\"publish\\**\" />\n  <EmbeddedResource Remove=\"publish\\**\" />\n  <None Remove=\"publish\\**\" />\n  <TypeScriptCompile Remove=\"**\\node_modules\\**\" />\n</ItemGroup>\n```\n\n### Integration Benefits\n\n- **Modern TypeScript** - Latest language features and better type checking\n- **Updated Node.js Types** - Compatibility with Node.js 22.x APIs\n- **ESLint Integration** - Better code quality and consistency\n- **MSBuild Compilation** - Integrated with Visual Studio build process\n\n## Troubleshooting Advanced Scenarios\n\n### Multi-Project Solutions\n\nWhen using ElectronNET.Core in multi-project solutions:\n\n1. **Install ElectronNET.Core.Api** in class library projects\n2. **Install ElectronNET.Core and ElectronNET.Core.AspNet** only in the startup project\n3. **Share configuration** through project references or shared files\n\n\n## Next Steps\n\n- **[Migration Guide](Migration-Guide.md)** - Complete migration process\n- **[What's New?](What's-New.md)** - Overview of all ElectronNET.Core features\n- **[Getting Started](../GettingStarted/ASP.Net.md)** - Development workflows\n"
  },
  {
    "path": "docs/Core/Migration-Checks.md",
    "content": "# Migration Checks\n\nElectron.NET includes automatic build-time validation checks that help users migrating from previous versions avoid common configuration issues. These checks run automatically during the build process and provide helpful guidance when problems are detected.\n\n## Overview\n\nWhen you build an Electron.NET project, the following validation checks are performed:\n\n| Code | Check | Description |\n|------|-------|-------------|\n| [ELECTRON001](#1-packagejson-rules) | package.json location rules | Ensures `package.json`/`package-lock.json` aren’t present in unsupported locations (root `package.json` handled separately) |\n| [ELECTRON008](#1-packagejson-rules) | root package.json contains electron | Warns when root `package.json` contains the word `electron` (case-insensitive) |\n| [ELECTRON009](#1-packagejson-rules) | root package.json copied to output | Warns when root `package.json` is configured to be copied to output/publish |\n| [ELECTRON002](#2-electron-manifestjson-not-allowed) | electron-manifest.json not allowed | Detects deprecated manifest files |\n| [ELECTRON003](#3-electron-builderjson-location) | electron-builder.json location | Verifies electron-builder.json exists in Properties folder |\n| [ELECTRON004](#3-electron-builderjson-location) | electron-builder.json wrong location | Warns if electron-builder.json is found in incorrect locations |\n| [ELECTRON005](#4-parent-paths-not-allowed-in-electron-builderjson) | Parent paths not allowed | Checks for `..` references in config |\n| [ELECTRON006](#5-publish-profile-validation) | ASP.NET publish profile mismatch | Warns when ASP.NET projects have console-style profiles |\n| [ELECTRON007](#5-publish-profile-validation) | Console publish profile mismatch | Warns when console projects have ASP.NET-style profiles |\n\n---\n\n## 1. package.json rules\n\n**Warning Codes:** `ELECTRON001`, `ELECTRON008`, `ELECTRON009`\n\n### What is checked\n\nThe build system scans for `package.json` and `package-lock.json` files in your project directory.\n\nRules:\n\n- **ELECTRON001**: `package.json` / `package-lock.json` must not exist in the project directory or subdirectories\n  - Exception: `ElectronHostHook` folder is allowed\n  - Note: a **root** `package.json` is **excluded** from `ELECTRON001` and validated by `ELECTRON008` / `ELECTRON009`\n\n- **ELECTRON008**: If a root `package.json` exists, it must **not** contain electron-related dependencies or configuration.\n\n- **ELECTRON009**: If a root `package.json` exists, it must **not** be configured to be copied to output/publish (for example via `CopyToOutputDirectory` / `CopyToPublishDirectory` metadata)\n\n### Why this matters\n\nElectron.NET generates its Electron-related `package.json` during publishing based on MSBuild properties. A user-maintained Electron-related `package.json` can conflict with that process.\n\nAlso, ensuring the root `package.json` is not copied prevents accidentally shipping it with the published app.\n\n### Exception\n\nA `package.json` / `package-lock.json` file **is allowed** in the `ElectronHostHook` folder if you're using custom host hooks.\n\n### How to fix\n\nIf you have an Electron-related `package.json` from older Electron.NET versions:\n\n1. **Open your project's `.csproj` file**\n2. **Add the required properties** to a PropertyGroup with the label `ElectronNetCommon`:\n\n```xml\n<PropertyGroup Label=\"ElectronNetCommon\">\n  <ElectronPackageId>my-electron-app</ElectronPackageId>\n  <Title>My Electron App</Title>\n  <Version>1.0.0</Version>\n  <Description>My awesome Electron.NET application</Description>\n  <Company>My Company</Company>\n  <Copyright>Copyright © 2025</Copyright>\n  <ElectronVersion>30.0.9</ElectronVersion>\n</PropertyGroup>\n```\n\n3. **Delete** Electron-related `package.json` / `package-lock.json` files (except those under `ElectronHostHook` if applicable)\n\nIf you keep a root `package.json` for non-Electron reasons:\n\n- Ensure it does **not** contain electron dependencies or configuration (fixes `ELECTRON008`)\n- Ensure it is **not** copied to output/publish (fixes `ELECTRON009`)\n\n> **See also:** [Migration Guide](Migration-Guide.md) for complete migration instructions.\n\n---\n\n## 2. electron-manifest.json not allowed\n\n**Warning Code:** `ELECTRON002`\n\n### What is checked\n\nThe build system checks for the presence of `electron.manifest.json` or `electron-manifest.json` files in your project.\n\n### Why this matters\n\nThe `electron.manifest.json` file format is deprecated. All configuration should now be specified using:\n- MSBuild properties in your `.csproj` file (for application metadata)\n- The `electron-builder.json` file in the `Properties` folder (for build configuration)\n\n### How to fix\n\n1. **Migrate application properties** to your `.csproj` file (see [Migration Guide](Migration-Guide.md))\n2. **Move the `build` section** from `electron.manifest.json` to `Properties/electron-builder.json`\n3. **Delete the old `electron.manifest.json`** file\n\n**Example electron-builder.json:**\n```json\n{\n    \"compression\": \"maximum\",\n    \"win\": {\n        \"icon\": \"Assets/app.ico\",\n        \"target\": [\"nsis\", \"portable\"]\n    },\n    \"linux\": {\n        \"icon\": \"Assets/app.png\",\n        \"target\": [\"AppImage\", \"deb\"]\n    },\n    \"mac\": {\n        \"icon\": \"Assets/app.icns\",\n        \"target\": [\"dmg\", \"zip\"]\n    }\n}\n```\n\n---\n\n## 3. electron-builder.json Location\n\n**Warning Codes:** `ELECTRON003`, `ELECTRON004`\n\n### What is checked\n\n- `ELECTRON003`: Verifies that an `electron-builder.json` file exists in the `Properties` folder\n- `ELECTRON004`: Warns if `electron-builder.json` is found in incorrect locations\n\n### Why this matters\n\nThe `electron-builder.json` file must be located in the `Properties` folder so it can be properly copied to the output directory during publishing.\n\n### How to fix\n\n1. **Create the Properties folder** if it doesn't exist\n2. **Move or create** `electron-builder.json` in `Properties/electron-builder.json`\n3. **Remove** any `electron-builder.json` files from other locations\n\n**Expected structure:**\n```\nMyProject/\n├── Properties/\n│   ├── electron-builder.json    ✅ Correct location\n│   ├── launchSettings.json\n│   └── PublishProfiles/\n├── MyProject.csproj\n└── Program.cs\n```\n\n---\n\n## 4. Parent paths not allowed in electron-builder.json\n\n**Warning Code:** `ELECTRON005`\n\n### What is checked\n\nThe build system scans the `electron-builder.json` file for parent-path references (`..`).\n\n### Why this matters\n\nDuring the publish process, the `electron-builder.json` file is copied to the build output directory. Any relative paths in this file are resolved from that location, not from your project directory. Parent-path references (`../`) will not work correctly because they would point outside the published application.\n\n### How to fix\n\n1. **Move resource files** (icons, installers, etc.) inside your project folder structure\n2. **Configure the files** to be copied to the output directory in your `.csproj`:\n\n```xml\n<ItemGroup>\n  <Content Include=\"Assets\\**\\*\">\n    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n  </Content>\n</ItemGroup>\n```\n\n3. **Update paths** in `electron-builder.json` to use relative paths without `..`:\n\n**Before (incorrect):**\n```json\n{\n    \"win\": {\n        \"icon\": \"../SharedAssets/app.ico\"\n    }\n}\n```\n\n**After (correct):**\n```json\n{\n    \"win\": {\n        \"icon\": \"Assets/app.ico\"\n    }\n}\n```\n\n---\n\n## 5. Publish Profile Validation\n\n**Warning Codes:** `ELECTRON006`, `ELECTRON007`\n\n### What is checked\n\nThe build system examines `.pubxml` files in the `Properties/PublishProfiles` folder and validates that they match the project type:\n\n- **ELECTRON006**: For **ASP.NET projects** (using `Microsoft.NET.Sdk.Web`), checks that publish profiles include `WebPublishMethod`. This property is required for proper ASP.NET publishing.\n\n- **ELECTRON007**: For **console/other projects** (not using the Web SDK), checks that publish profiles do NOT include the `WebPublishMethod`  property. These ASP.NET-specific properties are incorrect for non-web applications.\n\n### Why this matters\n\nElectron.NET supports both ASP.NET and console application project types, each requiring different publish profile configurations:\n\n| Project Type | SDK | Expected Properties |\n|--------------|-----|---------------------|\n| ASP.NET (Razor Pages, MVC, Blazor) | `Microsoft.NET.Sdk.Web` | `WebPublishMethod`, no `PublishProtocol` |\n| Console Application | `Microsoft.NET.Sdk` | `PublishProtocol`, no `WebPublishMethod` |\n\nUsing the wrong publish profile type can lead to incomplete or broken builds.\n\n### How to fix\n\n1. **Delete existing publish profiles** from `Properties/PublishProfiles/`\n2. **Create new publish profiles** using the Visual Studio Publishing Wizard:\n   - Right-click on the project in Solution Explorer\n   - Select **Publish...**\n   - Follow the wizard to create a **Folder** publish profile\n\nFor correct publish profile examples for both ASP.NET and Console applications, see **[Package Building](../Using/Package-Building.md#step-1-create-publish-profiles)**.\n\n---\n\n## Disabling Migration Checks\n\nIf you need to disable specific migration checks (not recommended), you can set the following properties in your `.csproj` file:\n\n```xml\n<PropertyGroup>\n  <!-- Disable all migration checks -->\n  <ElectronSkipMigrationChecks>true</ElectronSkipMigrationChecks>\n</PropertyGroup>\n```\n\n> ⚠️ **Warning:** Disabling migration checks may result in build or runtime errors. Only disable checks if you fully understand the implications.\n\n---\n\n## See Also\n\n- [Migration Guide](Migration-Guide.md) - Complete step-by-step migration instructions\n- [Advanced Migration Topics](Advanced-Migration-Topics.md) - Complex migration scenarios\n- [Configuration](../Using/Configuration.md) - Project configuration options\n- [Package Building](../Using/Package-Building.md) - Building distributable packages\n"
  },
  {
    "path": "docs/Core/Migration-Guide.md",
    "content": "# Migration Guide\n\nMigrating from previous versions of Electron.NET to ElectronNET.Core is straightforward but requires several important changes. This guide walks you through the process step by step.\n\n## 📋 Prerequisites\n\nBefore starting the migration:\n\n- **Backup your project** - Ensure you have a working backup\n- **Update development tools** - Install Node.js 22.x and .NET 8.0+\n- **Review current setup** - Note your current Electron and ASP.NET versions\n\n## 🚀 Migration Steps\n\n### Step 1: Update NuGet Packages\n\n**Uninstall old packages:**\n```powershell\ndotnet remove package  ElectronNET.API\n```\n\n**Install new packages:**\n```powershell\ndotnet add package ElectronNET.Core\ndotnet add package ElectronNET.Core.AspNet  # For ASP.NET projects\n```\n\n> **Note**: The API package is automatically included as a dependency of `ElectronNET.Core`. See [Package Description](../RelInfo/Package-Description.md) for details about the package structure.\n\n\n### Step 2: Configure Project Settings\n\n**Auto-generated Configuration:**  \nElectronNET.Core automatically creates `electron-builder.json` in the `Properties` folder of your project during the first build or NuGet restore. No manual configuration is needed for basic setups.\n\n**Migrate Existing Configuration:**  \nIf you have an existing `electron.manifest.json` file:\n\n1. **Open the generated `electron-builder.json`** file in your project\n2. **Locate the 'build' section** in your old `electron.manifest.json`\n3. **Copy the contents** of the build section (not the \"build\" key itself) into the new `electron-builder.json`\n4. **Use Visual Studio Project Designer** to configure Electron settings through the UI\n5. **Delete the old `electron.manifest.json`** file\n\n**Alternative: Manual Configuration**\nYou can also manually edit `electron-builder.json`:\n\n```json\n{\n  \"linux\": {\n    \"target\": [\n      \"tar.xz\"\n    ]\n  },\n  \"win\": {\n    \"target\": [\n      {\n        \"target\": \"portable\",\n        \"arch\": \"x64\"\n      }\n    ]\n  }\n}\n```\n\n**Modify Launch Settings:**\nElectronNET.Core no longer needs a separate CLI tool (electronize.exe) for launching. You should update your launch settings to use either the ASP.NET-first or Electron-first approach. See [Debugging](../Using/Debugging.md) for details.\n\n## 🎯 Testing Migration\n\nAfter completing the migration steps:\n\n1. **Build your project** to ensure no compilation errors\n2. **Test debugging** using the new ASP.NET-first approach\n3. **Verify packaging** works with the new configuration\n4. **Check cross-platform builds** if targeting multiple platforms\n\n## 🚨 Common Migration Issues\n\n### Build Errors\n- **Node.js version**: Verify Node.js 22.x is installed and in PATH\n- **Package conflicts**: Clean NuGet cache if needed\n\n### Runtime Errors\n- **Missing electron-builder.json**: Trigger rebuild or manual NuGet restore\n- **Process termination**: Use .NET-first startup mode for better cleanup\n\n## 🚀 Next Steps\n\n- **[What's New?](What's-New.md)** - Complete overview of ElectronNET.Core features\n- **[Advanced Migration Topics](Advanced-Migration-Topics.md)** - Handle complex scenarios\n- **[Getting Started](../GettingStarted/ASP.Net.md)** - Learn about new development workflows\n\n## 💡 Migration Benefits\n\n✅ **Simplified Configuration** - No more CLI tools or JSON files  \n✅ **Better Debugging** - Native Visual Studio experience with Hot Reload  \n✅ **Modern Architecture** - .NET-first process lifecycle  \n✅ **Cross-Platform Ready** - Build Linux apps from Windows  \n✅ **Future-Proof** - Flexible Electron version selection  \n\n### Step 3: Update Startup Code\n\n**Update UseElectron() calls** to include the new callback parameter. This callback executes at the right moment to initialize your Electron UI.\n\n#### Modern ASP.NET Core (WebApplication)\n\n```csharp\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\n    public static void Main(string[] args)\n    {\n        var builder = WebApplication.CreateBuilder(args);\n\n        builder.UseElectron(args, ElectronAppReady);\n\n        var app = builder.Build();\n        app.Run();\n    }\n\n    public static async Task ElectronAppReady()\n    {\n        var browserWindow = await Electron.WindowManager.CreateWindowAsync(\n            new BrowserWindowOptions { Show = false });\n\n        browserWindow.OnReadyToShow += () => browserWindow.Show();\n    }\n```\n\n#### Traditional ASP.NET Core (IWebHostBuilder)\n\n```csharp\t\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\n    public static void Main(string[] args)\n    {\n        WebHost.CreateDefaultBuilder(args)\n            .UseElectron(args, ElectronAppReady)\n            .UseStartup<Startup>()\n            .Build()\n            .Run();\n    }\n\n    public static async Task ElectronAppReady()\n    {\n        var browserWindow = await Electron.WindowManager.CreateWindowAsync(\n            new BrowserWindowOptions { Show = false });\n\n        browserWindow.OnReadyToShow += () => browserWindow.Show();\n    }\n```\n\n\n### Step 4: Update Development Tools\n\nSee [System Requirements](../GettingStarted/System-Requirements.md).\n\n### Step 5: Update Debugging Setup\n\n**Watch Feature Removal:**\n\nThe old 'watch' feature is no longer supported. Instead, use the new ASP.NET-first debugging with Hot Reload:\n\n- **Old approach**: Manual process attachment and slow refresh\n- **New approach**: Native Visual Studio debugging with Hot Reload\n- **Benefits**: Faster development cycle, better debugging experience\n\n**Update Launch Settings:**\n\nReplace old watch configurations with new debugging profiles. See [Debugging](../GettingStarted/Debugging.md) for detailed setup instructions.\n\n"
  },
  {
    "path": "docs/Core/What's-New.md",
    "content": "# What's New in ElectronNET.Core\n\n## A Complete Transformation\n\nElectronNET.Core represents a fundamental modernization of Electron.NET, addressing years of accumulated pain points while preserving full API compatibility. This isn't just an update—it's a complete rethinking of how .NET developers build and debug cross-platform desktop applications with Electron.\n\n## Complete Build System Overhaul\n\n### From CLI Complexity to MSBuild Simplicity\n\nThe most visible change is the complete elimination of the CLI tool dependency. Where developers once needed to manage complex command-line operations and JSON configuration files, everything now flows through Visual Studio's native project system.\n\nThe old `electron.manifest.json` file is gone, replaced by clean MSBuild project properties that integrate seamlessly with Visual Studio's project designer. This provides not just a better development experience, but also eliminates entire categories of configuration errors that plagued earlier versions.\n\n### Intelligent Package Structure\n\nThe new package architecture reflects a clearer separation of concerns:\n\n- **ElectronNET.Core** - The main package containing build logic and project system integration\n- **ElectronNET.Core.Api** - Pure API definitions for Electron integration\n- **ElectronNET.Core.AspNet** - ASP.NET-specific runtime components\n\nThis modular approach allows projects to include only what they need while maintaining the flexibility to scale from simple console applications to complex web applications.  \nMore about the available nuget packages: [Package Description](../RelInfo/Package-Description.md).\n\n## Beyond ASP.NET: Console Application Support\n\n### A Shift in Accessibility\n\nA major new opportunity in ElectronNET.Core is the removal of the ASP.NET requirement. Developers can now build Electron solutions using simple DotNet console applications, expanding the use cases and removing a major barrier to adoption for a number of use cases.\n\n### Flexible Content Sources\n\nConsole applications with ElectronNET.Core support multiple content scenarios:\n\n- **File System HTML/JS**: Serve static web content directly from the file system\n- **Remote Server Integration**: Connect to existing web servers or APIs\n- **Lightweight Architecture**: Avoid the overhead of ASP.NET when it's not needed\n- **Simplified Deployment**: Package and distribute with minimal dependencies\n\nThis capability transforms ElectronNET from a web-focused framework into a versatile platform that can integrate with any HTML/JS content source, making it accessible to a much broader range of development scenarios and team structures.\n\n## Revolutionary Development Experience\n\n### Debugging Reimagined\n\nThe debugging experience has been completely transformed. The new DotNet-first launch mode means developers can now debug their .NET code directly, with full access to familiar debugging tools and Hot Reload capabilities. No more attaching to processes or working around limited debugging scenarios — the development workflow now matches standard .NET development patterns.\n\n### Cross-Platform Development Without Compromises\n\nOne of the most significant breakthroughs is the ability to build and debug Linux applications directly from Windows Visual Studio through WSL integration. Developers can now:\n\n- Build Linux packages while working on Windows\n- Debug Linux application behavior in real-time\n- Test cross-platform functionality without context switching\n- Deploy to Linux targets with confidence\n\nThis capability eliminates the traditional barriers between Windows development environments and Linux deployment targets.\n\n### Flexible Runtime Identifier Support\n\nRuntime Identifier (RID) selection is now a first-class part of the project configuration, allowing developers to explicitly target specific platforms and architectures. The build system automatically structures output folders using standard .NET conventions (`bin\\net8.0\\win-x64`) instead of the ambiguous `bin\\Desktop` layout, making multi-target builds clean and predictable.\n\n## Modernized Architecture\n\n### Process Lifecycle Revolution\n\nThe underlying process architecture has been fundamentally redesigned. Instead of Electron launching first and managing the .NET process, ElectronNET.Core puts .NET in control. The .NET application launches first and runs Electron as a child process, providing:\n\n- Better process lifecycle management\n- More reliable application termination\n- Enhanced error handling and recovery\n- Cleaner separation between web and native concerns\n\nThis architecture supports eight different launch scenarios, covering every combination of packaged/unpackaged deployment, console/ASP.NET hosting, and dotnet-first/electron-first initialization. The Electron-first launch method is still available or course.  \nFor more details, see: [Startup Methods](../GettingStarted/Startup-Methods.md).\n\n### Unpackaged Development Mode\n\nThe new unpackaged run-mode transforms development workflows by using regular .NET builds with unpackaged Electron configurations. This approach leverages .NET's incremental build capabilities for both managed and native code, dramatically reducing rebuild times and improving the development feedback loop.\n\n## Enhanced Technical Foundation\n\n### TypeScript Integration\n\nTypeScript compilation is now fully integrated with ASP.NET tooling, providing consistent builds across different development environments. The updated toolchain uses modern TypeScript versions with ESLint configuration, eliminating the compatibility issues that previously affected custom ElectronHostHook implementations.\n\n### API Enhancements\n\nThe improved splash screen handling with automatic path resolution eliminates common configuration pitfalls, while maintaining full backward compatibility with existing ElectronHostHook code.\n\n### Performance Optimizations\n\nPackage sizes have been reduced by eliminating unnecessary dependencies, while build performance has improved through intelligent incremental compilation. The new architecture also minimizes startup times through optimized build and launch procedures.\n\n## Seamless Migration Path\n\n### Backward Compatibility Focus\n\nDespite the extensive changes, ElectronNET.Core maintains complete API compatibility with existing applications. The modular package structure allows for incremental adoption, and existing ElectronHostHook implementations continue to work without modification.\n\n### Clear Upgrade Journey\n\nThe migration path is designed to be straightforward:\n1. Update package references to the new structure\n2. Remove the old manifest file\n3. Configure project properties through Visual Studio\n4. Adopt new debugging workflows at your own pace  \n\nFurther reading: [Migration Guide](Migration-Guide.md).\n\n## Future Horizons\n\n### Unlocked Possibilities\n\nThis modernization removes the technical debt that was limiting Electron.NET's evolution. The flexible Electron versioning, integrated build system, and cross-platform capabilities create a foundation for:\n\n- More frequent updates and feature additions\n- Enhanced community contributions\n- Better tooling and IDE integration\n- Expanded platform support\n\n### Version Independence\n\nThe removal of rigid Electron version coupling means developers can now choose the Electron version that best fits their needs, with build-time validation ensuring compatibility. This approach encourages community feedback and enables faster adoption of new Electron features.\n\n## Conclusion\n\nElectronNET.Core represents more than just new features—it's a complete reimagining of what .NET + Electron development can be. By eliminating friction points, removing the ASP.NET requirement to support console applications, improving debugging experiences, and enabling true cross-platform development, it transforms Electron.NET from a challenging framework to work with into a modern, efficient platform for building cross-platform desktop applications.\n\nThe changes address the core issues that were driving developers away from Electron.NET while opening new possibilities for the future. This foundation will enable more rapid innovation and better support for the growing demands of cross-platform .NET development.\n"
  },
  {
    "path": "docs/Docs.shproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>06caadc7-de5b-47b4-ab2a-e9501459a2d1</ProjectGuid>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Remove=\"About\\Azure\\**\" />\n    <Compile Remove=\"About\\BuildBot\\**\" />\n    <Compile Remove=\"images\\AzureDevOps\\**\" />\n    <Compile Remove=\"images\\visualization\\**\" />\n    <Compile Remove=\"schema_printing\\**\" />\n    <EmbeddedResource Remove=\"About\\Azure\\**\" />\n    <EmbeddedResource Remove=\"About\\BuildBot\\**\" />\n    <EmbeddedResource Remove=\"images\\AzureDevOps\\**\" />\n    <EmbeddedResource Remove=\"images\\visualization\\**\" />\n    <EmbeddedResource Remove=\"schema_printing\\**\" />\n    <None Remove=\"About\\Azure\\**\" />\n    <None Remove=\"About\\BuildBot\\**\" />\n    <None Remove=\"images\\AzureDevOps\\**\" />\n    <None Remove=\"images\\visualization\\**\" />\n    <None Remove=\"schema_printing\\**\" />\n  </ItemGroup>\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <Import Project=\".docproj\\DocProj.props\" />\n  <Import Project=\".docproj\\DocProj.targets\" />\n</Project>"
  },
  {
    "path": "docs/GettingStarted/ASP.Net.md",
    "content": "\n# ASP.NET Core Setup\n\nASP.NET Core remains the recommended approach for complex web applications with ElectronNET.Core, providing all the benefits of the ASP.NET ecosystem along with enhanced Electron integration.\n\n## 🛠 System Requirements\n\nSee [System Requirements](../GettingStarted/System-Requirements.md).\n\n\n## 🚀 Quick Start\n\n### 1. Create ASP.NET Core Project\n\n#### Visual Studio\n\nCreate a new ASP.NET Core Web App in Visual Studio by selecting **New Project** and choosing one of the ASP.NET Core project templates.\n\n#### From the command line\n\n```bash\ndotnet new webapp -n MyElectronWebApp\ncd MyElectronWebApp\n```\n\n### 2. Install NuGet Packages\n\n#### Visual Studio\n\nRight-click the solution and select **Manage Nuget Packages**. \nFinr and install `ElectronNET.Core` as well as `ElectronNET.Core.AspNet`.\n\n#### From the command line\n\n```powershell\ndotnet add package ElectronNET.Core\ndotnet add package ElectronNET.Core.AspNet\n```\n\n> [!Note]  \n> The API package is automatically included as a dependency of `ElectronNET.Core`.\n\n\n### 3. Configure Program.cs\n\nUpdate your `Program.cs` to enable Electron.NET:\n\n```csharp\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\npublic class Program\n{\n    public static void Main(string[] args)\n    {\n        var builder = WebApplication.CreateBuilder(args);\n\n        builder.Services.AddRazorPages();\n\n        // Add this line to enable Electron.NET:\n        builder.UseElectron(args, ElectronAppReady);\n\n        var app = builder.Build();\n\n        if (!app.Environment.IsDevelopment())\n        {\n            app.UseExceptionHandler(\"/Error\");\n        }\n        app.UseStaticFiles();\n\n        app.UseRouting();\n\n        app.UseAuthorization();\n\n        app.MapRazorPages();\n\n        app.Run();\n    }\n\n    public static async Task ElectronAppReady()\n    {\n        var browserWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false });\n\n        browserWindow.OnReadyToShow += () => browserWindow.Show();\n    }\n}\n```\n\n#### ASP.NET Port\n\nIf you want to launch a specific URL, you can retrieve the actual ASP.NET port from the new `ElectronNetRuntime` static class, for example:\n\n```csharp\n    await browserWindow.WebContents\n        .LoadURLAsync($\"http://localhost:{ElectronNetRuntime.AspNetWebPort}/mypage.html\");\n```\n\n### 4. Alternative: IWebHostBuilder Setup\n\nFor projects using the traditional `Startup.cs` pattern, please see \"Traditional ASP.NET Core\" in the [Migration Guide](../Core/Migration-Guide.md).\n\n\n### 5. Dependency Injection\n\nElectronNET.API can be added to your DI container within the `Startup` class. All of the modules available in Electron will be added as Singletons.\n\n```csharp\nusing ElectronNET.API;\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddElectron();\n}\n```\n\n\n## 🚀 Next Steps\n\n- **[Debugging](../Using/Debugging.md)** - Learn about ASP.NET debugging features\n- **[Package Building](../Using/Package-Building.md)** - Create distributable packages\n- **[Startup Methods](../Using/Startup-Methods.md)** - Understanding launch scenarios\n\n## 💡 Benefits of ASP.NET + Electron\n\n✅ **Full Web Stack** - Use MVC, Razor Pages, Blazor, and all ASP.NET features  \n✅ **Hot Reload** - Edit ASP.NET code and see changes instantly  \n✅ **Rich Ecosystem** - Access to thousands of ASP.NET packages  \n✅ **Modern Development** - Latest C# features and ASP.NET patterns  \n✅ **Scalable Architecture** - Build complex, maintainable applications  \n"
  },
  {
    "path": "docs/GettingStarted/Console-App.md",
    "content": "\n\n# Console Application Setup\n\nA major benefit in ElectronNET.Core is the ability to build Electron applications using simple console applications instead of requiring ASP.NET Core. This removes a significant barrier and enables many more use cases.\n\n## 🎯 What You Can Build\n\nConsole applications with ElectronNET.Core support multiple content scenarios:\n\n- **File System HTML/JS** - Serve static web content directly from the file system\n- **Remote Server Integration** - Connect to existing web servers or APIs\n- **Lightweight Architecture** - Avoid ASP.NET overhead when not needed\n- **Simplified Deployment** - Package and distribute with minimal dependencies\n\n## 📋 Prerequisites\n\nSee [System Requirements](../GettingStarted/System-Requirements.md).\n\n\n## 🚀 Quick Start\n\n### 1. Create Console Application\n\n#### Visual Studio\n\nCreate a new console application in Visual Studio by selecting **New Project** and choosing one of the project templates for console apps.\n\n#### From the command line\n\n```bash\ndotnet new console -n MyElectronApp\ncd MyElectronApp\n```\n\n### 2. Install NuGet Packages\n\n```powershell\ndotnet add package ElectronNET.Core\n```\n\n> [!Note]  \n> The API package is automatically included as a dependency of `ElectronNET.Core`.\n\n### 3. Configure Project File\n\nAdd the Electron.NET configuration to your `.csproj` file:\n\n```xml\n<PropertyGroup>\n  <OutputType>Exe</OutputType>\n  <TargetFramework>net10.0</TargetFramework>\n  <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n</PropertyGroup>\n\n<ItemGroup>\n  <PackageReference Include=\"ElectronNET.Core\" Version=\"0.4.1\" />\n</ItemGroup>\n```\n\n> [!WARNING]  \n> Specifying `OutputType` property is crucial in order to get the ability of WSL debugging. Especially it is not included in ASP.NET projects.  \n> When you migrate from ASP.NET to a console application, be sure to add this to the project file.\n\n\n### 4. Implement Basic Structure\n\nHere's a complete console application example:\n\n```csharp\nusing System;\nusing System.Threading.Tasks;\nusing ElectronNET.API.Entities;\n\nnamespace MyElectronApp\n\npublic class Program\n{\n    public static async Task Main(string[] args)\n    {\n        var runtimeController = ElectronNetRuntime.RuntimeController;\n\n        try\n        {\n            // Start Electron runtime\n            await runtimeController.Start();\n            await runtimeController.WaitReadyTask;\n\n            // Initialize your Electron app\n            await InitializeApp();\n\n            // Wait for shutdown\n            await runtimeController.WaitStoppedTask.ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            Console.WriteLine($\"Error: {ex.Message}\");\n            await runtimeController.Stop().ConfigureAwait(false);\n            await runtimeController.WaitStoppedTask.WaitAsync(TimeSpan.FromSeconds(2)).ConfigureAwait(false);\n        }\n    }\n\n    private static async Task InitializeApp()\n    {\n        // Create main window\n        var browserWindow = await Electron.WindowManager.CreateWindowAsync(\n            new BrowserWindowOptions\n            {\n                Show = false,\n                WebPreferences = new WebPreferences\n                {\n                    // Add these two when using file:// URLs\n                    WebSecurity = false,\n                    AllowRunningInsecureContent = true,\n\n                    NodeIntegration = false,\n                    ContextIsolation = true\n                }\n            });\n\n        // Load your content (file system, remote URL, etc.)\n        await browserWindow.WebContents.LoadURLAsync(\"https://example.com\");\n\n        // Show window when ready\n        browserWindow.OnReadyToShow += () => browserWindow.Show();\n    }\n}\n```\n\n## 📁 Content Sources\n\n### File System Content\n\nServe HTML/JS files from your project:\n\n```csharp\n// In your project root, create wwwroot/index.html\nvar fileInfo = new FileInfo(Environment.ProcessPath);\nvar exeFolder = fileInfo.DirectoryName;\nvar htmlPath = Path.Combine(exeFolder, \"wwwroot/index.html\");\nvar url = new Uri(htmlPath, UriKind.Absolute);\nawait browserWindow.WebContents.LoadFileAsync(url.ToString());\n```\n\n### Remote Content\n\nLoad content from any web server:\n\n```csharp\nawait browserWindow.WebContents.LoadURLAsync(\"https://your-server.com/app\");\n```\n\n\n## 🚀 Next Steps\n\n- **[Debugging](../Using/Debugging.md)** - Learn about debugging console applications\n- **[Package Building](../Using/Package-Building.md)** - Create distributable packages\n- **[Migration Guide](../Core/Migration-Guide.md)** - Moving from ASP.NET projects\n\n## 💡 Benefits of Console Apps\n\n✅ **Simpler Architecture** - No ASP.NET complexity when not needed  \n✅ **Flexible Content** - Use any HTML/JS source  \n✅ **Faster Development** - Less overhead for simple applications  \n✅ **Easy Deployment** - Minimal dependencies  \n✅ **Better Performance** - Lighter weight than full web applications  \n"
  },
  {
    "path": "docs/GettingStarted/System-Requirements.md",
    "content": "\n## 🛠 System Requirements\n\n### Required Software\n\n- **.NET 8.0** or later\n- **Node.js 22.x** or later (see below)\n- **Visual Studio 2022** (recommended) or other .NET IDE\n\n### Supported Operating Systems\n\n- **Windows 10/11** (x64, ARM64)\n- **macOS 11+** (Intel, Apple Silicon)\n- **Linux** (most distributions with glibc 2.31+)\n\n> [!Note]  \n> For Linux development on Windows, install [WSL2](https://docs.microsoft.com/windows/wsl/install) to build and debug Linux packages.\n> Do not forget to install NodeJS 22.x (LTS) on WSL.  \n> Visual Studio will automatically install .NET when debugging on WSL. In all other cases you will need to install a matching .NET SDK on WSL as well.\n\n\n### NodeJS Installation\n\n\nElectronNET.Core requires Node.js 22.x. Update your installation:\n\n**Windows:**\n\n1. Download from [nodejs.org](https://nodejs.org)\n2. Run the installer\n3. Verify: `node --version` should show v22.x.x\n\n**Linux:**\n\n```bash\n# Using Node Version Manager (recommended)\ncurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash\nsource ~/.bashrc\nnvm install 22\nnvm use 22\n\n# Or using package manager\nsudo apt update\nsudo apt install nodejs=22.*\n```\n\n\n## 🚀 Next Steps\n\n- **[Debugging](../Using/Debugging.md)** - Learn about ASP.NET debugging features\n- **[Package Building](../Using/Package-Building.md)** - Create distributable packages\n- **[Startup Methods](../Using/Startup-Methods.md)** - Understanding launch scenarios\n\n"
  },
  {
    "path": "docs/Home.md",
    "content": "\n\n# Electron.NET Wiki Home\n\nWelcome to the **Electron.NET Core** documentation! This wiki covers everything you need to know about building cross-platform desktop applications with ASP.NET Core and Electron.NET.\n\n## 🚀 What is Electron.NET Core?\n\nElectron.NET Core is a complete modernization of Electron.NET that eliminates the CLI tool dependency and integrates deeply with Visual Studio's MSBuild system. It transforms the development experience by providing:\n\n- **Native Visual Studio Integration** - No more CLI tools or JSON configuration files\n- **Console Application Support** - Build Electron apps with simple console applications, not just ASP.NET\n- **Cross-Platform Development** - Build and debug Linux applications from Windows via WSL\n- **Enhanced Debugging** - ASP.NET-first debugging with Hot Reload support\n- **Flexible Architecture** - Choose any Electron version and target multiple platforms\n\n## 📚 Documentation Sections\n\n### [Core Documentation](Core/What's-New.md)\n- **[What's New?](Core/What's-New.md)** - Complete overview of ElectronNET.Core features and improvements\n- **[Migration Guide](Core/Migration-Guide.md)** - Step-by-step migration from previous versions\n- **[Advanced Migration Topics](Core/Advanced-Migration-Topics.md)** - Technical details for complex scenarios\n\n### [Getting Started](GettingStarted/ASP.Net.md)\n- **[ASP.NET Applications](GettingStarted/ASP.Net.md)** - Build Electron apps with ASP.NET Core\n- **[Console Applications](GettingStarted/Console-App.md)** - Use console apps for file system or remote content\n- **[Startup Methods](GettingStarted/Startup-Methods.md)** - Understanding different launch scenarios\n- **[Debugging](GettingStarted/Debugging.md)** - Debug Electron apps effectively in Visual Studio\n- **[Package Building](GettingStarted/Package-Building.md)** - Create distributable packages\n\n### [Release Information](RelInfo/Package-Description.md)\n- **[Package Description](RelInfo/Package-Description.md)** - Understanding the three NuGet packages\n- **[Changelog](../Changelog.md)** - Complete list of changes and improvements\n\n## 🛠 System Requirements\n\nSee [System Requirements](GettingStarted/System-Requirements.md).\n\n## 💡 Key Benefits\n\n✅ **No CLI Tools Required** - Everything works through Visual Studio  \n✅ **Console App Support** - Use any HTML/JS source, not just ASP.NET  \n✅ **True Cross-Platform** - Build Linux apps from Windows  \n✅ **Modern Debugging** - Hot Reload and ASP.NET-first debugging  \n✅ **Flexible Packaging** - Choose any Electron version  \n✅ **MSBuild Integration** - Leverages .NET's build system  \n\n## 🚦 Getting Started\n\nNew to ElectronNET.Core? Start here:\n\n1. **[ASP.NET Setup](GettingStarted/ASP.Net.md)** - Traditional web application approach\n2. **[Console App Setup](GettingStarted/Console-App.md)** - Lightweight console application approach\n3. **[Migration Guide](Core/Migration-Guide.md)** - Moving from previous versions\n\n## 🤝 Contributing\n\nFound an issue or want to improve the documentation? Contributions are welcome!   \nThe wiki is auto-generated from the `/docs` folder in the [GitHub repository](https://github.com/ElectronNET/Electron.NET).\n"
  },
  {
    "path": "docs/RelInfo/Package-Description.md",
    "content": "# Package Description\n\nElectronNET.Core consists of three specialized NuGet packages designed for different development scenarios and project architectures.\n\n## 📦 Package Overview\n\n### ElectronNET.Core (Main Package)\n**Primary package for Electron.NET applications**\n\n- **Build system integration** - MSBuild targets and tasks for Electron\n- **Project system extensions** - Visual Studio designer integration\n- **Runtime orchestration** - Process lifecycle management\n- **Automatic configuration** - Generates electron-builder.json and package.json\n- **Includes ElectronNET.Core.Api** as a dependency\n\n**When to use:**\n- Main application projects (startup projects)\n- Projects that need full Electron.NET functionality\n- Applications requiring build-time Electron configuration\n\n### ElectronNET.Core.Api (API Package)\n**Pure API definitions without build integration**\n\n- **Electron API wrappers** - Complete Electron API surface\n- **Type definitions** - Full TypeScript-style IntelliSense\n- **No build dependencies** - Clean API-only package\n- **Multi-platform support** - Windows, macOS, Linux\n\n**When to use:**\n- Class library projects that interact with Electron APIs\n- Projects that only need API access without build integration\n- Multi-project solutions where only the startup project needs build integration\n\n### ElectronNET.Core.AspNet (ASP.NET Integration)\n**ASP.NET-specific runtime components**\n\n- **ASP.NET middleware** - UseElectron() extension methods\n- **WebHost integration** - Seamless ASP.NET + Electron hosting\n- **Hot Reload support** - Enhanced debugging experience\n- **Web-specific optimizations** - ASP.NET tailored performance\n\n**When to use:**\n- ASP.NET Core projects building Electron applications\n- Applications requiring web server functionality\n- Projects using MVC, Razor Pages, or Blazor\n\n## 🏗 Architecture Benefits\n\n### Separation of Concerns\n- **Build logic separate from API** - Clean dependency management\n- **Optional ASP.NET integration** - Use only what you need\n- **Multi-project friendly** - Share APIs across projects without build conflicts\n\n### Project Scenarios\n\n**Single Project (ASP.NET):**\n```xml\n<ItemGroup>\n  <PackageReference Include=\"ElectronNET.Core\" Version=\"1.0.0\" />\n  <PackageReference Include=\"ElectronNET.Core.AspNet\" Version=\"1.0.0\" />\n</ItemGroup>\n```\n\n**Single Project (Console):**\n```xml\n<ItemGroup>\n  <PackageReference Include=\"ElectronNET.Core\" Version=\"1.0.0\" />\n</ItemGroup>\n```\n\n**Multi-Project Solution (ASP.NET):**\n```xml\n<!-- Startup project -->\n<ItemGroup>\n  <PackageReference Include=\"ElectronNET.Core\" Version=\"1.0.0\" />\n  <PackageReference Include=\"ElectronNET.Core.AspNet\" Version=\"1.0.0\" />\n</ItemGroup>\n\n<!-- Class library projects -->\n<ItemGroup>\n  <PackageReference Include=\"ElectronNET.Core.Api\" Version=\"1.0.0\" />\n</ItemGroup>\n```\n\n**Multi-Project Solution (Console):**\n```xml\n<!-- Startup project -->\n<ItemGroup>\n  <PackageReference Include=\"ElectronNET.Core\" Version=\"1.0.0\" />\n</ItemGroup>\n\n<!-- Class library projects -->\n<ItemGroup>\n  <PackageReference Include=\"ElectronNET.Core.Api\" Version=\"1.0.0\" />\n</ItemGroup>\n```\n\n## 🔗 Dependency Chain\n\n```\nElectronNET.Core.AspNet  →  ElectronNET.Core.Api\n\nElectronNET.Core  →  ElectronNET.Core.Api\n```\n\n- **ElectronNET.Core.AspNet** depends on ElectronNET.Core.Api\n- **ElectronNET.Core** depends on ElectronNET.Core.Api\n- **ElectronNET.Core.Api** has no dependencies\n\n## 💡 Recommendations\n\n✅ **Start with ElectronNET.Core** for new projects  \n✅ **Add ElectronNET.Core.AspNet** only for ASP.NET applications  \n✅ **Use ElectronNET.Core.Api** for class libraries and API-only scenarios  \n✅ **Multi-project solutions** benefit from the modular architecture  \n\n"
  },
  {
    "path": "docs/Using/Configuration.md",
    "content": "\n# Project Configuration\n\n\n## 🔧 Visual Studio App Designer\n\nElectron.NET provides close integration via the Visual Studio Project System and MSBuild. After adding the ElectronNET.Core package, you will see this in the project configuration page after double-click on the 'Properties' folder or right-click on the project and choosing 'Properties':\n\n\n![App Designer1](../images/app_designer1.png)\n\n![App Designer2](../images/app_designer2.png)\n\n\n## Project File Settings\n\nThe same settings can be configured manually by editing the MSBuild properties in your `.csproj` file.  \nThese are the current default values when you don't make any changes:\n\n```xml\n<PropertyGroup Label=\"ElectronNetCommon\">\n    <ElectronVersion>30.4.0</ElectronVersion>\n    <ElectronBuilderVersion>26.0</ElectronBuilderVersion>\n    <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n    <ElectronSingleInstance>true</ElectronSingleInstance>\n    <ElectronSplashScreen></ElectronSplashScreen>\n    <ElectronIcon></ElectronIcon>\n    <ElectronPackageId>$(MSBuildProjectName.Replace(\".\", \"-\").ToLower())</ElectronPackageId>\n    <ElectronBuilderJson>electron-builder.json</ElectronBuilderJson>\n    <Title>$(MSBuildProjectName)</Title>\n</PropertyGroup>\n```\n\n### Relation to package.json\n\nElectronNET.Core does not work with an `electron-manifest.json` file anymore.\nSince electron builder still expects a `package.json` file to exist, ElectronNET.Core is creating this under the hood automatically during build. For reference, here's the package.json template file that is being used, so you can see how the MSBuild properties are being mapped to `package.json` data:\n\n```json\n{\n  \"name\": \"$(ElectronPackageId)\",\n  \"productName\": \"$(ElectronTitle)\",\n  \"build\": {\n    \"appId\": \"$(ElectronPackageId)\",\n    \"linux\": {\n      \"desktop\": {\n        \"entry\": { \"Name\": \"$(Title)\" }\n      },\n      \"executableName\": \"$(ElectronPackageId)\"\n    },\n    \"deb\": {\n      \"desktop\": {\n        \"entry\": { \"Name\": \"$(Title)\" }\n      }\n    }\n  },\n  \"description\": \"$(Description)\",\n  \"version\": \"$(Version)\",\n  \"main\": \"main.js\",\n  \"author\": {\n    \"name\": \"$(Company)\"\n  },\n  \"license\": \"$(License)\",\n  \"executable\": \"$(TargetName)\",\n  \"singleInstance\": \"$(ElectronSingleInstance)\",\n  \"homepage\": \"$(ProjectUrl)\",\n  \"splashscreen\": {\n    \"imageFile\": \"$(ElectronSplashScreen)\"\n  }\n}\n```\n\n### Node.js Integration\n\nElectron.NET requires Node.js integration to be enabled for IPC to function. If you are not using the IPC functionality you can disable Node.js integration like so:\n\n```csharp\nWebPreferences wp = new WebPreferences();\nwp.NodeIntegration = false;\nBrowserWindowOptions browserWindowOptions = new BrowserWindowOptions\n{\n    WebPreferences = wp\n};\n\n```\n\n\n### Preload Script\n\nIf you require the use of a [preload script](https://www.electronjs.org/docs/latest/tutorial/tutorial-preload), you can specify the file path of the script when creating a new window like so:\n\n```csharp\nWebPreferences wp = new WebPreferences();\nwp.Preload = \"path/to/preload.js\";\nBrowserWindowOptions browserWindowOptions = new BrowserWindowOptions\n{\n    WebPreferences = wp\n};\n```\n\n> [!IMPORTANT]\n> When using a preload script _AND_ running a Blazor app, `IsRunningBlazor` must be set to `false` (or removed) and the following lines must be added to the preload script:\n> ```js\n> global.process = undefined;\n> global.module = undefined;\n> ```\n\n\n## 🚀 Next Steps\n\n- **[Startup Methods](Startup-Methods.md)** - Understanding launch scenarios\n- **[Debugging](../Using/Debugging.md)** - Learn about ASP.NET debugging features\n- **[Package Building](Package-Building.md)** - Create distributable packages\n\n"
  },
  {
    "path": "docs/Using/Custom_main.md",
    "content": "# Using custom_main.js\n\nThis guide explains how to include and use a `custom_main.js` file in your Electron.NET application for advanced Electron/Node.js customization.\n\n## Why use custom_main.js?\n\n- Register custom protocol handlers (e.g., `myapp://`) — protocols must be registered before the app is fully initialized\n- Integrate Node.js modules (e.g., telemetry, OS APIs)\n- Control startup logic (abort, environment checks)\n- Set up IPC messaging or preload scripts\n\n## Step-by-Step Process\n\n### 1. Create the custom_main.js file\n\nPlace your custom logic in `electron/custom_main.js`:\n\n```javascript\nmodule.exports.onStartup = function(host) {\n    // Example: Register a global shortcut for opening dev tools\n    const { app, globalShortcut, BrowserWindow } = require('electron');\n    app.on('ready', () => {\n        const ret = globalShortcut.register('Control+Shift+I', () => {\n            BrowserWindow.getAllWindows().forEach(win => win.webContents.openDevTools());\n            console.log('Ctrl+Shift+I is pressed: DevTools opened!');\n        });\n    });\n    app.on('will-quit', () => {\n        globalShortcut.unregisterAll();\n    });\n    return true;\n};\n```\n\n### 2. Configure your .csproj to copy custom_main.js to output\n\nAdd this to your `.csproj` file:\n\n```xml\n<ItemGroup>\n  <None Update=\"electron\\custom_main.js\">\n    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    <TargetPath>.electron\\custom_main.js</TargetPath>\n  </None>\n</ItemGroup>\n```\n\n### 3. Build and run your app\n\nUse the standard build/run commands:\n\n```powershell\ndotnet build\ndotnet run\n```\n\nElectron.NET will automatically load and execute your `custom_main.js` before initializing the .NET backend.\n\n## Advanced Usage\n\nUse environment variables to control features:\n\n  ```javascript\n  const env = process.env.ASPNETCORE_ENVIRONMENT || 'Production';\n  if (env === 'Development') { /* enable dev features */ }\n  ```\n\n## Notes\n\n- `custom_main.js` must use CommonJS syntax (`module.exports.onStartup = ...`).\n- Place the file in your source directory and copy it to `.electron` using `.csproj`.\n- Electron.NET will abort startup if `onStartup` returns `false`.\n\n### Complete example is available here [ElectronNetSampleApp](https://github.com/niteshsinghal85/ElectronNetSampleApp)"
  },
  {
    "path": "docs/Using/Debugging.md",
    "content": "# Debugging\n\nElectronNET.Core transforms the debugging experience by providing native Visual Studio integration with multiple debugging modes. No more complex setup or manual process attachment—debugging now works as expected for .NET developers.\n\n## 🎯 Debugging Modes\n\nElectronNET.Core supports three main debugging approaches, all configured through Visual Studio's launch profiles:\n\n### 1. ASP.NET-First Debugging (Recommended)\n\nDebug your .NET code directly with full Hot Reload support:\n\n```json\n{\n  \"profiles\": {\n    \"ASP.Net (unpackaged)\": {\n      \"commandName\": \"Project\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      },\n      \"applicationUrl\": \"http://localhost:8001/\"\n    }\n  }\n}\n```\n\n**Benefits:**\n- ✅ Full C# debugging with breakpoints\n- ✅ Hot Reload for ASP.NET code\n- ✅ Edit-and-continue functionality\n- ✅ Native Visual Studio debugging experience\n\n### 2. Electron-First Debugging\n\nDebug the Electron process when you need to inspect native Electron APIs:\n\n```json\n{\n  \"profiles\": {\n    \"Electron (unpackaged)\": {\n      \"commandName\": \"Executable\",\n      \"executablePath\": \"node\",\n      \"commandLineArgs\": \"node_modules/electron/cli.js main.js -unpackedelectron\",\n      \"workingDirectory\": \"$(TargetDir).electron\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    }\n  }\n}\n```\n\n**Benefits:**\n- ✅ Debug Electron main process\n- ✅ Inspect native Electron APIs\n- ✅ Node.js debugging capabilities\n\n### 3. Cross-Platform WSL Debugging\n\nDebug Linux builds directly from Windows Visual Studio:\n\n```json\n{\n  \"profiles\": {\n    \"WSL\": {\n      \"commandName\": \"WSL2\",\n      \"launchUrl\": \"http://localhost:8001/\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_URLS\": \"http://localhost:8001/\"\n      },\n      \"distributionName\": \"\"\n    }\n  }\n}\n```\n\n**Benefits:**\n- ✅ Debug Linux applications from Windows\n- ✅ Test Linux-specific behavior\n- ✅ Validate cross-platform compatibility\n\n## 🔧 Setup Instructions\n\n### 1. Configure Launch Settings\n\nAdd the debugging profiles to `Properties/launchSettings.json`:\n\n```json\n{\n  \"profiles\": {\n    \"ASP.Net (unpackaged)\": {\n      \"commandName\": \"Project\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      },\n      \"applicationUrl\": \"http://localhost:8001/\"\n    },\n    \"Electron (unpackaged)\": {\n      \"commandName\": \"Executable\",\n      \"executablePath\": \"node\",\n      \"commandLineArgs\": \"node_modules/electron/cli.js main.js -unpackedelectron\",\n      \"workingDirectory\": \"$(TargetDir).electron\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"WSL\": {\n      \"commandName\": \"WSL2\",\n      \"launchUrl\": \"http://localhost:8001/\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_URLS\": \"http://localhost:8001/\"\n      },\n      \"distributionName\": \"\"\n    }\n  }\n}\n```\n\n### 2. Switch Runtime Identifiers\n\nWhen switching between Windows and WSL debugging:\n\n1. **Right-click your project** in Solution Explorer\n2. Select **Properties**\n3. Adjust the Runtime Identifier\n\n\nWithout Visual Studio:\n\n1. **Edit** the .csproj file\n2. **Update the RuntimeIdentifier**:\n\n```xml\n<!-- For Windows debugging -->\n<RuntimeIdentifier>win-x64</RuntimeIdentifier>\n\n<!-- For WSL/Linux debugging -->\n<RuntimeIdentifier>linux-x64</RuntimeIdentifier>\n```\n\n### 3. Enable WSL Debugging\n\nFor WSL debugging, ensure:\n\n- **WSL2 is installed** and configured\n- **Linux distribution** is set in the launch profile\n- **Project targets Linux RID** for WSL debugging\n\n## 🚀 Debugging Workflow\n\n### ASP.NET-First Debugging (Default)\n\n1. **Select \"ASP.Net (unpackaged)\"** profile in Visual Studio\n2. **Press F5** to start debugging\n3. **Set breakpoints** in your C# code\n4. **Use Hot Reload** to edit ASP.NET code during runtime\n5. **Stop debugging** when finished\n\n### Electron Process Debugging\n\n1. **Select \"Electron (unpackaged)\"** profile\n2. **Press F5** to start debugging\n3. **Attach to Electron process** if needed\n4. **Debug Node.js and Electron APIs**\n\n### Cross-Platform Debugging\n\n1. **Set RuntimeIdentifier** to `linux-x64`\n2. **Select \"WSL\"** profile\n3. **Press F5** to debug in WSL\n4. **Test Linux-specific behavior**\n\n## 🔍 Debugging Tips\n\n### Hot Reload\n\n- **Works with ASP.NET-first debugging**\n- **Edit Razor views, controllers, and pages**\n- **See changes instantly** without restart\n- **Preserves application state**\n\n### Breakpoint Debugging\n\n```csharp\n// Set breakpoints here\npublic async Task<IActionResult> Index()\n{\n    var data = await GetData(); // ← Breakpoint\n    return View(data);\n}\n```\n\n### Process Management\n\n- **ASP.NET-first mode** automatically manages Electron process lifecycle\n- **Proper cleanup** on debugging session end\n- **No manual process killing** required\n\n## 🛠 Troubleshooting\n\n### Common Issues\n\n**\"Electron process not found\"**\n- Ensure Node.js 22.x is installed\n- Check that packages are restored (`dotnet restore`)\n- Verify RuntimeIdentifier matches your target platform\n\n**\"WSL debugging fails\"**\n- Install and configure WSL2\n- Ensure Linux distribution is properly set up\n- Check that project targets correct RID\n\n**\"Hot Reload not working\"**\n- Use ASP.NET-first debugging profile\n- Ensure ASPNETCORE_ENVIRONMENT=Development\n- Check for compilation errors\n\n## 🎨 Visual Debugging\n\n*Placeholder for image showing Visual Studio debugging interface with Electron.NET*\n\nThe debugging interface provides familiar Visual Studio tools:\n- **Locals and Watch windows** for variable inspection\n- **Call Stack** for method call tracing\n- **Immediate Window** for runtime evaluation\n- **Hot Reload** indicator for edit-and-continue\n\n## 🚀 Next Steps\n\n- **[Startup Methods](Startup-Methods.md)** - Understanding different launch scenarios\n- **[Package Building](Package-Building.md)** - Debug packaged applications\n- **[Migration Guide](../Core/Migration-Guide.md)** - Moving from old debugging workflows\n\n## 💡 Benefits\n\n✅ **Native Visual Studio Experience** - No complex setup or manual attachment  \n✅ **Hot Reload Support** - Edit ASP.NET code during debugging  \n✅ **Cross-Platform Debugging** - Debug Linux apps from Windows  \n✅ **Multiple Debugging Modes** - Choose the right approach for your needs  \n✅ **Process Lifecycle Management** - Automatic cleanup and proper termination  \n"
  },
  {
    "path": "docs/Using/Package-Building.md",
    "content": "# Package Building\n\nElectronNET.Core integrates with Visual Studio's publishing system to create distributable Electron packages using electron-builder. The process leverages .NET's build system while automatically generating the necessary Electron configuration files.\n\n## 🎯 Publishing Overview\n\nThe publishing process differs slightly between ASP.NET and console applications:\n\n- **ASP.NET Apps** - Use folder publishing with SelfContained=true\n- **Console Apps** - Use folder publishing with SelfContained=false\n\n\n## 🚀 Publishing Process\n\n### Step 1: Create Publish Profiles\n\nAdd publish profiles to `Properties/PublishProfiles/`:\n\n#### ASP.NET Application Profile (Windows)\n\n**win-x64.pubxml:**\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <DeleteExistingFiles>true</DeleteExistingFiles>\n    <PublishProvider>FileSystem</PublishProvider>\n    <PublishUrl>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishUrl>\n    <WebPublishMethod>FileSystem</WebPublishMethod>\n    <_TargetId>Folder</_TargetId>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n    <ProjectGuid>48eff821-2f4d-60cc-aa44-be0f1d6e5f35</ProjectGuid>\n    <SelfContained>true</SelfContained>\n  </PropertyGroup>\n</Project>\n```\n\n#### ASP.NET Application Profile (Linux)\n\n**linux-x64.pubxml:**\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <DeleteExistingFiles>true</DeleteExistingFiles>\n    <PublishProvider>FileSystem</PublishProvider>\n    <PublishUrl>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishUrl>\n    <WebPublishMethod>FileSystem</WebPublishMethod>\n    <_TargetId>Folder</_TargetId>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>\n    <ProjectGuid>48eff821-2f4d-60cc-aa44-be0f1d6e5f35</ProjectGuid>\n    <SelfContained>true</SelfContained>\n  </PropertyGroup>\n</Project>\n```\n\n#### ASP.NET Application Profile (macOS Apple Silicon ARM64)\n\n**osx-arm64.pubxml:**\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <DeleteExistingFiles>true</DeleteExistingFiles>\n    <PublishProvider>FileSystem</PublishProvider>\n    <PublishUrl>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishUrl>\n    <WebPublishMethod>FileSystem</WebPublishMethod>\n    <_TargetId>Folder</_TargetId>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>osx-arm64</RuntimeIdentifier>\n    <ProjectGuid>48eff821-2f4d-60cc-aa44-be0f1d6e5f35</ProjectGuid>\n    <SelfContained>true</SelfContained>\n  </PropertyGroup>\n</Project>\n```\n\n#### ASP.NET Application Profile (macOS Intel x64)\n\n**osx-x64.pubxml:**\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <DeleteExistingFiles>true</DeleteExistingFiles>\n    <PublishProvider>FileSystem</PublishProvider>\n    <PublishUrl>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishUrl>\n    <WebPublishMethod>FileSystem</WebPublishMethod>\n    <_TargetId>Folder</_TargetId>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>osx-x64</RuntimeIdentifier>\n    <ProjectGuid>48eff821-2f4d-60cc-aa44-be0f1d6e5f35</ProjectGuid>\n    <SelfContained>true</SelfContained>\n  </PropertyGroup>\n</Project>\n```\n\n#### Console Application Profile (Windows)\n\n**win-x64.pubxml:**\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <PublishDir>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishDir>\n    <PublishProtocol>FileSystem</PublishProtocol>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n    <SelfContained>false</SelfContained>\n    <PublishSingleFile>false</PublishSingleFile>\n    <PublishReadyToRun>false</PublishReadyToRun>\n  </PropertyGroup>\n</Project>\n```\n\n#### Console Application Profile (Linux)\n\n**linux-x64.pubxml:**\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <PublishDir>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishDir>\n    <PublishProtocol>FileSystem</PublishProtocol>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>\n    <SelfContained>false</SelfContained>\n    <PublishSingleFile>false</PublishSingleFile>\n  </PropertyGroup>\n</Project>\n```\n\n#### Console Application Profile (macOS Apple Silicon ARM64)\n\n**osx-arm64.pubxml:**\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <PublishDir>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishDir>\n    <PublishProtocol>FileSystem</PublishProtocol>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>osx-arm64</RuntimeIdentifier>\n    <SelfContained>false</SelfContained>\n    <PublishSingleFile>false</PublishSingleFile>\n  </PropertyGroup>\n</Project>\n```\n\n#### Console Application Profile (macOS Intel x64)\n\n**osx-x64.pubxml:**\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <PublishDir>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishDir>\n    <PublishProtocol>FileSystem</PublishProtocol>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>osx-x64</RuntimeIdentifier>\n    <SelfContained>false</SelfContained>\n    <PublishSingleFile>false</PublishSingleFile>\n  </PropertyGroup>\n</Project>\n```\n\n### Step 2: Configure Electron Builder\n\nElectronNET.Core automatically adds a default `electron-builder.json` file under `Properties\\electron-builder.json`.  \nPlease see here for details of the available configuration options: https://www.electron.build/.\n\n\n### Step 3: Publish from Visual Studio\n\n1. **Right-click your project** in Solution Explorer\n2. **Select \"Publish\"**\n4. **Select your publish profile** (Windows/Linux)\n5. **Click \"Publish\"**\n\nThe publish process will:\n- Build your .NET application\n- Copy all files as needed\n- Install npm dependencies\n- Run electron-builder\n\n> [!NOTE]  \n> When running publish for a Linux configuration on Windows, Electron.NET will automatically use WSL for the platform-specific steps.\n\n**After publishing**, the final results will be in \n\n`publish\\Release\\netx.0\\xxx-xxx\\`\n\n\n## MacOS\n\n> [!NOTE]\n> macOS builds can't be created on Windows machines because they require symlinks that aren't supported on Windows (per [this Electron issue](https://github.com/electron-userland/electron-packager/issues/71)). macOS builds can be produced on either Linux or macOS machines.\n\n\n## 🚀 Next Steps\n\n- **[Startup Methods](Startup-Methods.md)** - Understanding different launch modes for packaged apps\n- **[Debugging](Debugging.md)** - Debug packaged applications\n- **[Migration Guide](../Core/Migration-Guide.md)** - Update existing projects for new publishing\n\n## 💡 Benefits\n\n✅ **Native VS Integration** - Use familiar publish workflows  \n✅ **Cross-Platform Building** - Build Linux packages from Windows  \n✅ **Automatic Configuration** - No manual electron-builder setup  \n✅ **Multiple Package Types** - NSIS, AppImage, DMG, etc.  \n✅ **CI/CD Ready** - Easy integration with build pipelines  \n"
  },
  {
    "path": "docs/Using/Startup-Methods.md",
    "content": "# Startup Methods\n\nElectronNET.Core supports multiple startup methods to handle different development and deployment scenarios. The framework automatically detects the appropriate mode based on command-line flags and environment.\n\n## 🎯 Startup Scenarios\n\nThe framework supports **8 different launch scenarios** covering every combination of:\n\n- **Packaged vs Unpackaged** deployment\n- **Console vs ASP.NET** application types\n- **Dotnet-first vs Electron-first** initialization\n\n## 🚀 Command-Line Flags\n\n### Unpackaged Debugging Modes\n\n#### **`-unpackedelectron`** - Electron-first debugging\n```bash\n# Launch Electron first, which then starts .NET\nnode node_modules/electron/cli.js main.js -unpackedelectron\n```\n\n#### **`-unpackeddotnet`** - .NET-first debugging\n```bash\n# Launch .NET first, which then starts Electron\ndotnet run -unpackeddotnet\n```\n\n### Packaged Deployment Modes\n\n#### **`-dotnetpacked`** - .NET-first packaged execution\n```bash\n# Run packaged app with .NET starting first\nMyApp.exe -dotnetpacked\n```\n\n#### **No flags** - Electron-first packaged execution (default)\n```bash\n# Run packaged app with Electron starting first\nMyApp.exe\n```\n\n## 📋 Startup Method Details\n\n### 1. Unpackaged + Electron-First (Development)\n- **Use Case**: Debug Electron main process and Node.js code\n- **Command**: `-unpackedelectron` flag\n- **Process Flow**:\n  1. Electron starts first\n  2. Electron launches .NET process\n  3. .NET connects back to Electron\n  4. Application runs with Electron in control\n\n### 2. Unpackaged + .NET-First (Development)\n- **Use Case**: Debug ASP.NET/C# code with Hot Reload\n- **Command**: `-unpackeddotnet` flag\n- **Process Flow**:\n  1. .NET application starts first\n  2. .NET launches Electron process\n  3. Electron connects back to .NET\n  4. Application runs with .NET in control\n\n### 3. Packaged + .NET-First (Production)\n- **Use Case**: Deployed application with .NET controlling lifecycle\n- **Command**: `-dotnetpacked` flag\n- **Process Flow**:\n  1. .NET executable starts first\n  2. .NET launches Electron from packaged files\n  3. Electron loads from app.asar or extracted files\n  4. .NET maintains process control\n\n### 4. Packaged + Electron-First (Production)\n- **Use Case**: Traditional Electron app behavior\n- **Command**: No special flags\n- **Process Flow**:\n  1. Electron executable starts first\n  2. Electron launches .NET from packaged files\n  3. .NET runs from Electron's process context\n  4. Electron maintains UI control\n\n## 🔧 Configuration Examples\n\n### ASP.NET Application Startup\n\n```csharp\n// Program.cs\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure for different startup modes\nbuilder.WebHost.UseElectron(args, async () =>\n{\n    var browserWindow = await Electron.WindowManager.CreateWindowAsync(\n        new BrowserWindowOptions { Show = false });\n\n    await browserWindow.WebContents.LoadURLAsync(\"http://localhost:8001\");\n    browserWindow.OnReadyToShow += () => browserWindow.Show();\n});\n\nvar app = builder.Build();\napp.Run();\n```\n\n### Console Application Startup\n\n```csharp\n// Program.cs\npublic static async Task Main(string[] args)\n{\n    var runtimeController = ElectronNetRuntime.RuntimeController;\n\n    await runtimeController.Start();\n    await runtimeController.WaitReadyTask;\n\n    await InitializeApplication();\n\n    await runtimeController.WaitStoppedTask;\n}\n```\n\n## 🎨 Visual Process Flow\n\n\n![Startup Modes](../images/startup_modes.png)\n\nThe image above illustrates how each combination of deployment type, application type, and initialization order affects the process lifecycle.\n\n## 🚀 Development Workflows\n\n### Debugging Workflow\n\n**ASP.NET-First Debugging** (Recommended)\n```json\n// launchSettings.json\n{\n  \"ASP.Net (unpackaged)\": {\n    \"commandName\": \"Project\",\n    \"commandLineArgs\": \"-unpackeddotnet\"\n  }\n}\n```\n\n**Electron-First Debugging**\n```json\n// launchSettings.json\n{\n  \"Electron (unpackaged)\": {\n    \"commandName\": \"Executable\",\n    \"executablePath\": \"node\",\n    \"commandLineArgs\": \"node_modules/electron/cli.js main.js -unpackedelectron\"\n  }\n}\n```\n\n### Production Deployment\n\n**Dotnet-First Deployment**\n\n```bash\n# Build and package\ndotnet publish -c Release -r win-x64\ncd publish\\Release\\net8.0\\win-x64\nnpm install\nnpx electron-builder\n\n# Run with dotnet-first\nMyApp.exe -dotnetpacked\n```\n\n**Electron-First Deployment** (Default)\n\n```bash\n# Run packaged application (no special flags needed)\nMyApp.exe\n```\n\n## 🔍 Process Lifecycle Management\n\n### Automatic Cleanup\n\nElectronNET.Core automatically manages process lifecycle:\n\n- **Graceful shutdown** when main window is closed\n- **Proper cleanup** of child processes\n- **Error handling** for process failures\n- **Cross-platform compatibility** for process management\n\n### Manual Control\n\nAccess runtime controller for advanced scenarios:\n\n```csharp\nvar runtime = ElectronNetRuntime.RuntimeController;\n\n// Wait for Electron to be ready\nawait runtime.WaitReadyTask;\n\n// Stop Electron runtime\nawait runtime.Stop();\nawait runtime.WaitStoppedTask;\n```\n\n## 🛠 Troubleshooting\n\n### Common Startup Issues\n\n**\"Electron process not found\"**\n- Ensure Node.js 22.x is installed\n- Check that .NET build succeeded\n- Verify RuntimeIdentifier is set correctly\n\n**\"Port conflicts\"**\n- Use different ports for different startup modes\n- Check that no other instances are running\n- Verify firewall settings\n\n**\"Process won't terminate\"**\n- Use dotnet-first mode for better cleanup\n- Check for unhandled exceptions\n- Verify all windows are properly closed\n\n## 💡 Best Practices\n\n### Choose the Right Mode\n\n- **Development**: Use .NET-first for C# debugging, Electron-first for Node.js debugging\n- **Production**: Use .NET-first for better process control, Electron-first for traditional behavior\n- **Cross-platform**: Use .NET-first for consistent behavior across platforms\n\n### Environment Configuration\n\n```xml\n<!-- .csproj -->\n<PropertyGroup>\n  <ElectronNETCoreEnvironment>Production</ElectronNETCoreEnvironment>\n</PropertyGroup>\n```\n\n## 🚀 Next Steps\n\n- **[Debugging](Debugging.md)** - Debug different startup modes\n- **[Package Building](Package-Building.md)** - Package for different deployment scenarios\n- **[Migration Guide](../Core/Migration-Guide.md)** - Update existing apps for new startup methods\n\n## 🎯 Summary\n\nThe flexible startup system ensures ElectronNET.Core works optimally in every scenario while providing the control and debugging experience .NET developers expect. Choose the appropriate mode based on your development workflow and deployment requirements.\n"
  },
  {
    "path": "docs/_Footer.md",
    "content": " \nWant to contribute to this documentation? Please fork and create a PR! The Wiki is autogenerated from the /docs content in the repository."
  },
  {
    "path": "docs/_Sidebar.md",
    "content": "<!-- First line gets deleted -->\n\n# Wiki\n\n- [Home](Home.md)\n- [About this Project](About.md)\n\n# Electron.NET Core\n\n- [What's new?](Core/What's-New.md)\n- [Migration Guide](Core/Migration-Guide.md)\n- [Migration Checks](Core/Migration-Checks.md)\n- [Advanced Migration](Core/Advanced-Migration-Topics.md)\n\n# Getting Started\n\n- [System Requirements](GettingStarted/System-Requirements.md)\n- [With ASP.Net](GettingStarted/ASP.Net.md)\n- [With a Console App](GettingStarted/Console-App.md)\n\n# Using Electron.NET\n\n- [Configuration](Using/Configuration.md)\n- [Startup-Methods](Using/Startup-Methods.md)\n- [Debugging](Using/Debugging.md)\n- [Package Building](Using/Package-Building.md)\n- [Adding a `custom_main.js`](Using/Custom_main.md)\n\n# API Reference\n\n- [API Overview](API/Overview.md)\n- [Electron.App](API/App.md)\n- [Electron.Dialog](API/Dialog.md)\n- [Electron.Menu](API/Menu.md)\n- [Electron.WindowManager](API/WindowManager.md)\n- [Electron.Shell](API/Shell.md)\n- [Electron.Screen](API/Screen.md)\n- [Electron.Notification](API/Notification.md)\n- [Electron.Tray](API/Tray.md)\n- [Electron.Clipboard](API/Clipboard.md)\n- [Electron.Dock](API/Dock.md)\n- [Electron.HostHook](API/HostHook.md)\n- [Electron.IpcMain](API/IpcMain.md)\n- [Electron.GlobalShortcut](API/GlobalShortcut.md)\n- [Electron.AutoUpdater](API/AutoUpdater.md)\n- [Electron.NativeTheme](API/NativeTheme.md)\n- [Electron.PowerMonitor](API/PowerMonitor.md)\n\n#  Release Information\n\n- [Package Description](RelInfo/Package-Description.md)\n- [Changelog](RelInfo/Changelog.md)\n"
  },
  {
    "path": "docs/md-styles.css",
    "content": "/*!\n * Bootstrap v3.4.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n    font-family: sans-serif;\n    -ms-text-size-adjust: 100%;\n    -webkit-text-size-adjust: 100%\n}\n\narticle, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {\n    display: block\n}\n\naudio, canvas, progress, video {\n    display: inline-block;\n    vertical-align: baseline\n}\n\n    audio:not([controls]) {\n        display: none;\n        height: 0\n    }\n\n[hidden], template {\n    display: none\n}\n\na:active, a:hover {\n    outline: 0\n}\n\nabbr[title] {\n    border-bottom: none;\n    text-decoration: underline;\n    -webkit-text-decoration: underline dotted;\n    -moz-text-decoration: underline dotted;\n    text-decoration: underline dotted\n}\n\nb, optgroup, strong {\n    font-weight: 700\n}\n\ndfn {\n    font-style: italic\n}\n\nh1 {\n    margin: .67em 0\n}\n\nmark {\n    background: #ff0;\n    color: #000\n}\n\nsub, sup {\n    font-size: 75%;\n    line-height: 0;\n    position: relative;\n    vertical-align: baseline\n}\n\nsup {\n    top: -.5em\n}\n\nsub {\n    bottom: -.25em\n}\n\nimg {\n    border: 0;\n    vertical-align: middle\n}\n\nsvg:not(:root) {\n    overflow: hidden\n}\n\nhr {\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    height: 0\n}\n\ncode, kbd, pre, samp {\n    font-size: 1em\n}\n\nbutton, input, optgroup, select, textarea {\n    color: inherit;\n    font: inherit;\n    margin: 0\n}\n\nbutton {\n    overflow: visible\n}\n\nbutton, select {\n    text-transform: none\n}\n\nbutton, html input[type=button], input[type=reset], input[type=submit] {\n    -webkit-appearance: button;\n    cursor: pointer\n}\n\n    button[disabled], html input[disabled] {\n        cursor: default\n    }\n\n    button::-moz-focus-inner, input::-moz-focus-inner {\n        border: 0;\n        padding: 0\n    }\n\ninput {\n    line-height: normal\n}\n\n    input[type=checkbox], input[type=radio] {\n        -webkit-box-sizing: border-box;\n        -moz-box-sizing: border-box;\n        box-sizing: border-box;\n        padding: 0\n    }\n\n    input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button {\n        height: auto\n    }\n\n    input[type=search] {\n        -webkit-appearance: textfield;\n        -webkit-box-sizing: content-box;\n        -moz-box-sizing: content-box;\n        box-sizing: content-box\n    }\n\n        input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration {\n            -webkit-appearance: none\n        }\n\ntextarea {\n    overflow: auto\n}\n\ntd, th {\n    padding: 0\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n    *, :after, :before {\n        color: #000 !important;\n        text-shadow: none !important;\n        background: 0 0 !important;\n        -webkit-box-shadow: none !important;\n        box-shadow: none !important\n    }\n\n    a, a:visited {\n        text-decoration: underline\n    }\n\n        a[href]:after {\n            content: \" (\" attr(href) \")\"\n        }\n\n    abbr[title]:after {\n        content: \" (\" attr(title) \")\"\n    }\n\n    a[href^=\"#\"]:after, a[href^=\"javascript:\"]:after {\n        content: \"\"\n    }\n\n    blockquote, pre {\n        border: 1px solid #999;\n        page-break-inside: avoid\n    }\n\n    thead {\n        display: table-header-group\n    }\n\n    img, tr {\n        page-break-inside: avoid\n    }\n\n    img {\n        max-width: 100% !important\n    }\n\n    h2, h3, p {\n        orphans: 3;\n        widows: 3\n    }\n\n    h2, h3 {\n        page-break-after: avoid\n    }\n\n    .navbar {\n        display: none\n    }\n\n    .btn > .caret, .dropup > .btn > .caret {\n        border-top-color: #000 !important\n    }\n\n    .label {\n        border: 1px solid #000\n    }\n\n    .table {\n        border-collapse: collapse !important\n    }\n\n        .table td, .table th {\n            background-color: #fff !important\n        }\n\n    .table-bordered td, .table-bordered th {\n        border: 1px solid #ddd !important\n    }\n}\n\n@font-face {\n    font-family: \"Glyphicons Halflings\";\n    src: url(\"../fonts/glyphicons-halflings-regular.eot\");\n    src: url(\"../fonts/glyphicons-halflings-regular.eot?#iefix\") format(\"embedded-opentype\"),url(\"../fonts/glyphicons-halflings-regular.woff2\") format(\"woff2\"),url(\"../fonts/glyphicons-halflings-regular.woff\") format(\"woff\"),url(\"../fonts/glyphicons-halflings-regular.ttf\") format(\"truetype\"),url(\"../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular\") format(\"svg\")\n}\n\n.glyphicon {\n    position: relative;\n    top: 1px;\n    display: inline-block;\n    font-family: \"Glyphicons Halflings\";\n    font-style: normal;\n    font-weight: 400;\n    line-height: 1;\n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale\n}\n\n.glyphicon-asterisk:before {\n    content: \"\\002a\"\n}\n\n.glyphicon-plus:before {\n    content: \"\\002b\"\n}\n\n.glyphicon-eur:before, .glyphicon-euro:before {\n    content: \"\\20ac\"\n}\n\n.glyphicon-minus:before {\n    content: \"\\2212\"\n}\n\n.glyphicon-cloud:before {\n    content: \"\\2601\"\n}\n\n.glyphicon-envelope:before {\n    content: \"\\2709\"\n}\n\n.glyphicon-pencil:before {\n    content: \"\\270f\"\n}\n\n.glyphicon-glass:before {\n    content: \"\\e001\"\n}\n\n.glyphicon-music:before {\n    content: \"\\e002\"\n}\n\n.glyphicon-search:before {\n    content: \"\\e003\"\n}\n\n.glyphicon-heart:before {\n    content: \"\\e005\"\n}\n\n.glyphicon-star:before {\n    content: \"\\e006\"\n}\n\n.glyphicon-star-empty:before {\n    content: \"\\e007\"\n}\n\n.glyphicon-user:before {\n    content: \"\\e008\"\n}\n\n.glyphicon-film:before {\n    content: \"\\e009\"\n}\n\n.glyphicon-th-large:before {\n    content: \"\\e010\"\n}\n\n.glyphicon-th:before {\n    content: \"\\e011\"\n}\n\n.glyphicon-th-list:before {\n    content: \"\\e012\"\n}\n\n.glyphicon-ok:before {\n    content: \"\\e013\"\n}\n\n.glyphicon-remove:before {\n    content: \"\\e014\"\n}\n\n.glyphicon-zoom-in:before {\n    content: \"\\e015\"\n}\n\n.glyphicon-zoom-out:before {\n    content: \"\\e016\"\n}\n\n.glyphicon-off:before {\n    content: \"\\e017\"\n}\n\n.glyphicon-signal:before {\n    content: \"\\e018\"\n}\n\n.glyphicon-cog:before {\n    content: \"\\e019\"\n}\n\n.glyphicon-trash:before {\n    content: \"\\e020\"\n}\n\n.glyphicon-home:before {\n    content: \"\\e021\"\n}\n\n.glyphicon-file:before {\n    content: \"\\e022\"\n}\n\n.glyphicon-time:before {\n    content: \"\\e023\"\n}\n\n.glyphicon-road:before {\n    content: \"\\e024\"\n}\n\n.glyphicon-download-alt:before {\n    content: \"\\e025\"\n}\n\n.glyphicon-download:before {\n    content: \"\\e026\"\n}\n\n.glyphicon-upload:before {\n    content: \"\\e027\"\n}\n\n.glyphicon-inbox:before {\n    content: \"\\e028\"\n}\n\n.glyphicon-play-circle:before {\n    content: \"\\e029\"\n}\n\n.glyphicon-repeat:before {\n    content: \"\\e030\"\n}\n\n.glyphicon-refresh:before {\n    content: \"\\e031\"\n}\n\n.glyphicon-list-alt:before {\n    content: \"\\e032\"\n}\n\n.glyphicon-lock:before {\n    content: \"\\e033\"\n}\n\n.glyphicon-flag:before {\n    content: \"\\e034\"\n}\n\n.glyphicon-headphones:before {\n    content: \"\\e035\"\n}\n\n.glyphicon-volume-off:before {\n    content: \"\\e036\"\n}\n\n.glyphicon-volume-down:before {\n    content: \"\\e037\"\n}\n\n.glyphicon-volume-up:before {\n    content: \"\\e038\"\n}\n\n.glyphicon-qrcode:before {\n    content: \"\\e039\"\n}\n\n.glyphicon-barcode:before {\n    content: \"\\e040\"\n}\n\n.glyphicon-tag:before {\n    content: \"\\e041\"\n}\n\n.glyphicon-tags:before {\n    content: \"\\e042\"\n}\n\n.glyphicon-book:before {\n    content: \"\\e043\"\n}\n\n.glyphicon-bookmark:before {\n    content: \"\\e044\"\n}\n\n.glyphicon-print:before {\n    content: \"\\e045\"\n}\n\n.glyphicon-camera:before {\n    content: \"\\e046\"\n}\n\n.glyphicon-font:before {\n    content: \"\\e047\"\n}\n\n.glyphicon-bold:before {\n    content: \"\\e048\"\n}\n\n.glyphicon-italic:before {\n    content: \"\\e049\"\n}\n\n.glyphicon-text-height:before {\n    content: \"\\e050\"\n}\n\n.glyphicon-text-width:before {\n    content: \"\\e051\"\n}\n\n.glyphicon-align-left:before {\n    content: \"\\e052\"\n}\n\n.glyphicon-align-center:before {\n    content: \"\\e053\"\n}\n\n.glyphicon-align-right:before {\n    content: \"\\e054\"\n}\n\n.glyphicon-align-justify:before {\n    content: \"\\e055\"\n}\n\n.glyphicon-list:before {\n    content: \"\\e056\"\n}\n\n.glyphicon-indent-left:before {\n    content: \"\\e057\"\n}\n\n.glyphicon-indent-right:before {\n    content: \"\\e058\"\n}\n\n.glyphicon-facetime-video:before {\n    content: \"\\e059\"\n}\n\n.glyphicon-picture:before {\n    content: \"\\e060\"\n}\n\n.glyphicon-map-marker:before {\n    content: \"\\e062\"\n}\n\n.glyphicon-adjust:before {\n    content: \"\\e063\"\n}\n\n.glyphicon-tint:before {\n    content: \"\\e064\"\n}\n\n.glyphicon-edit:before {\n    content: \"\\e065\"\n}\n\n.glyphicon-share:before {\n    content: \"\\e066\"\n}\n\n.glyphicon-check:before {\n    content: \"\\e067\"\n}\n\n.glyphicon-move:before {\n    content: \"\\e068\"\n}\n\n.glyphicon-step-backward:before {\n    content: \"\\e069\"\n}\n\n.glyphicon-fast-backward:before {\n    content: \"\\e070\"\n}\n\n.glyphicon-backward:before {\n    content: \"\\e071\"\n}\n\n.glyphicon-play:before {\n    content: \"\\e072\"\n}\n\n.glyphicon-pause:before {\n    content: \"\\e073\"\n}\n\n.glyphicon-stop:before {\n    content: \"\\e074\"\n}\n\n.glyphicon-forward:before {\n    content: \"\\e075\"\n}\n\n.glyphicon-fast-forward:before {\n    content: \"\\e076\"\n}\n\n.glyphicon-step-forward:before {\n    content: \"\\e077\"\n}\n\n.glyphicon-eject:before {\n    content: \"\\e078\"\n}\n\n.glyphicon-chevron-left:before {\n    content: \"\\e079\"\n}\n\n.glyphicon-chevron-right:before {\n    content: \"\\e080\"\n}\n\n.glyphicon-plus-sign:before {\n    content: \"\\e081\"\n}\n\n.glyphicon-minus-sign:before {\n    content: \"\\e082\"\n}\n\n.glyphicon-remove-sign:before {\n    content: \"\\e083\"\n}\n\n.glyphicon-ok-sign:before {\n    content: \"\\e084\"\n}\n\n.glyphicon-question-sign:before {\n    content: \"\\e085\"\n}\n\n.glyphicon-info-sign:before {\n    content: \"\\e086\"\n}\n\n.glyphicon-screenshot:before {\n    content: \"\\e087\"\n}\n\n.glyphicon-remove-circle:before {\n    content: \"\\e088\"\n}\n\n.glyphicon-ok-circle:before {\n    content: \"\\e089\"\n}\n\n.glyphicon-ban-circle:before {\n    content: \"\\e090\"\n}\n\n.glyphicon-arrow-left:before {\n    content: \"\\e091\"\n}\n\n.glyphicon-arrow-right:before {\n    content: \"\\e092\"\n}\n\n.glyphicon-arrow-up:before {\n    content: \"\\e093\"\n}\n\n.glyphicon-arrow-down:before {\n    content: \"\\e094\"\n}\n\n.glyphicon-share-alt:before {\n    content: \"\\e095\"\n}\n\n.glyphicon-resize-full:before {\n    content: \"\\e096\"\n}\n\n.glyphicon-resize-small:before {\n    content: \"\\e097\"\n}\n\n.glyphicon-exclamation-sign:before {\n    content: \"\\e101\"\n}\n\n.glyphicon-gift:before {\n    content: \"\\e102\"\n}\n\n.glyphicon-leaf:before {\n    content: \"\\e103\"\n}\n\n.glyphicon-fire:before {\n    content: \"\\e104\"\n}\n\n.glyphicon-eye-open:before {\n    content: \"\\e105\"\n}\n\n.glyphicon-eye-close:before {\n    content: \"\\e106\"\n}\n\n.glyphicon-warning-sign:before {\n    content: \"\\e107\"\n}\n\n.glyphicon-plane:before {\n    content: \"\\e108\"\n}\n\n.glyphicon-calendar:before {\n    content: \"\\e109\"\n}\n\n.glyphicon-random:before {\n    content: \"\\e110\"\n}\n\n.glyphicon-comment:before {\n    content: \"\\e111\"\n}\n\n.glyphicon-magnet:before {\n    content: \"\\e112\"\n}\n\n.glyphicon-chevron-up:before {\n    content: \"\\e113\"\n}\n\n.glyphicon-chevron-down:before {\n    content: \"\\e114\"\n}\n\n.glyphicon-retweet:before {\n    content: \"\\e115\"\n}\n\n.glyphicon-shopping-cart:before {\n    content: \"\\e116\"\n}\n\n.glyphicon-folder-close:before {\n    content: \"\\e117\"\n}\n\n.glyphicon-folder-open:before {\n    content: \"\\e118\"\n}\n\n.glyphicon-resize-vertical:before {\n    content: \"\\e119\"\n}\n\n.glyphicon-resize-horizontal:before {\n    content: \"\\e120\"\n}\n\n.glyphicon-hdd:before {\n    content: \"\\e121\"\n}\n\n.glyphicon-bullhorn:before {\n    content: \"\\e122\"\n}\n\n.glyphicon-bell:before {\n    content: \"\\e123\"\n}\n\n.glyphicon-certificate:before {\n    content: \"\\e124\"\n}\n\n.glyphicon-thumbs-up:before {\n    content: \"\\e125\"\n}\n\n.glyphicon-thumbs-down:before {\n    content: \"\\e126\"\n}\n\n.glyphicon-hand-right:before {\n    content: \"\\e127\"\n}\n\n.glyphicon-hand-left:before {\n    content: \"\\e128\"\n}\n\n.glyphicon-hand-up:before {\n    content: \"\\e129\"\n}\n\n.glyphicon-hand-down:before {\n    content: \"\\e130\"\n}\n\n.glyphicon-circle-arrow-right:before {\n    content: \"\\e131\"\n}\n\n.glyphicon-circle-arrow-left:before {\n    content: \"\\e132\"\n}\n\n.glyphicon-circle-arrow-up:before {\n    content: \"\\e133\"\n}\n\n.glyphicon-circle-arrow-down:before {\n    content: \"\\e134\"\n}\n\n.glyphicon-globe:before {\n    content: \"\\e135\"\n}\n\n.glyphicon-wrench:before {\n    content: \"\\e136\"\n}\n\n.glyphicon-tasks:before {\n    content: \"\\e137\"\n}\n\n.glyphicon-filter:before {\n    content: \"\\e138\"\n}\n\n.glyphicon-briefcase:before {\n    content: \"\\e139\"\n}\n\n.glyphicon-fullscreen:before {\n    content: \"\\e140\"\n}\n\n.glyphicon-dashboard:before {\n    content: \"\\e141\"\n}\n\n.glyphicon-paperclip:before {\n    content: \"\\e142\"\n}\n\n.glyphicon-heart-empty:before {\n    content: \"\\e143\"\n}\n\n.glyphicon-link:before {\n    content: \"\\e144\"\n}\n\n.glyphicon-phone:before {\n    content: \"\\e145\"\n}\n\n.glyphicon-pushpin:before {\n    content: \"\\e146\"\n}\n\n.glyphicon-usd:before {\n    content: \"\\e148\"\n}\n\n.glyphicon-gbp:before {\n    content: \"\\e149\"\n}\n\n.glyphicon-sort:before {\n    content: \"\\e150\"\n}\n\n.glyphicon-sort-by-alphabet:before {\n    content: \"\\e151\"\n}\n\n.glyphicon-sort-by-alphabet-alt:before {\n    content: \"\\e152\"\n}\n\n.glyphicon-sort-by-order:before {\n    content: \"\\e153\"\n}\n\n.glyphicon-sort-by-order-alt:before {\n    content: \"\\e154\"\n}\n\n.glyphicon-sort-by-attributes:before {\n    content: \"\\e155\"\n}\n\n.glyphicon-sort-by-attributes-alt:before {\n    content: \"\\e156\"\n}\n\n.glyphicon-unchecked:before {\n    content: \"\\e157\"\n}\n\n.glyphicon-expand:before {\n    content: \"\\e158\"\n}\n\n.glyphicon-collapse-down:before {\n    content: \"\\e159\"\n}\n\n.glyphicon-collapse-up:before {\n    content: \"\\e160\"\n}\n\n.glyphicon-log-in:before {\n    content: \"\\e161\"\n}\n\n.glyphicon-flash:before {\n    content: \"\\e162\"\n}\n\n.glyphicon-log-out:before {\n    content: \"\\e163\"\n}\n\n.glyphicon-new-window:before {\n    content: \"\\e164\"\n}\n\n.glyphicon-record:before {\n    content: \"\\e165\"\n}\n\n.glyphicon-save:before {\n    content: \"\\e166\"\n}\n\n.glyphicon-open:before {\n    content: \"\\e167\"\n}\n\n.glyphicon-saved:before {\n    content: \"\\e168\"\n}\n\n.glyphicon-import:before {\n    content: \"\\e169\"\n}\n\n.glyphicon-export:before {\n    content: \"\\e170\"\n}\n\n.glyphicon-send:before {\n    content: \"\\e171\"\n}\n\n.glyphicon-floppy-disk:before {\n    content: \"\\e172\"\n}\n\n.glyphicon-floppy-saved:before {\n    content: \"\\e173\"\n}\n\n.glyphicon-floppy-remove:before {\n    content: \"\\e174\"\n}\n\n.glyphicon-floppy-save:before {\n    content: \"\\e175\"\n}\n\n.glyphicon-floppy-open:before {\n    content: \"\\e176\"\n}\n\n.glyphicon-credit-card:before {\n    content: \"\\e177\"\n}\n\n.glyphicon-transfer:before {\n    content: \"\\e178\"\n}\n\n.glyphicon-cutlery:before {\n    content: \"\\e179\"\n}\n\n.glyphicon-header:before {\n    content: \"\\e180\"\n}\n\n.glyphicon-compressed:before {\n    content: \"\\e181\"\n}\n\n.glyphicon-earphone:before {\n    content: \"\\e182\"\n}\n\n.glyphicon-phone-alt:before {\n    content: \"\\e183\"\n}\n\n.glyphicon-tower:before {\n    content: \"\\e184\"\n}\n\n.glyphicon-stats:before {\n    content: \"\\e185\"\n}\n\n.glyphicon-sd-video:before {\n    content: \"\\e186\"\n}\n\n.glyphicon-hd-video:before {\n    content: \"\\e187\"\n}\n\n.glyphicon-subtitles:before {\n    content: \"\\e188\"\n}\n\n.glyphicon-sound-stereo:before {\n    content: \"\\e189\"\n}\n\n.glyphicon-sound-dolby:before {\n    content: \"\\e190\"\n}\n\n.glyphicon-sound-5-1:before {\n    content: \"\\e191\"\n}\n\n.glyphicon-sound-6-1:before {\n    content: \"\\e192\"\n}\n\n.glyphicon-sound-7-1:before {\n    content: \"\\e193\"\n}\n\n.glyphicon-copyright-mark:before {\n    content: \"\\e194\"\n}\n\n.glyphicon-registration-mark:before {\n    content: \"\\e195\"\n}\n\n.glyphicon-cloud-download:before {\n    content: \"\\e197\"\n}\n\n.glyphicon-cloud-upload:before {\n    content: \"\\e198\"\n}\n\n.glyphicon-tree-conifer:before {\n    content: \"\\e199\"\n}\n\n.glyphicon-tree-deciduous:before {\n    content: \"\\e200\"\n}\n\n.glyphicon-cd:before {\n    content: \"\\e201\"\n}\n\n.glyphicon-save-file:before {\n    content: \"\\e202\"\n}\n\n.glyphicon-open-file:before {\n    content: \"\\e203\"\n}\n\n.glyphicon-level-up:before {\n    content: \"\\e204\"\n}\n\n.glyphicon-copy:before {\n    content: \"\\e205\"\n}\n\n.glyphicon-paste:before {\n    content: \"\\e206\"\n}\n\n.glyphicon-alert:before {\n    content: \"\\e209\"\n}\n\n.glyphicon-equalizer:before {\n    content: \"\\e210\"\n}\n\n.glyphicon-king:before {\n    content: \"\\e211\"\n}\n\n.glyphicon-queen:before {\n    content: \"\\e212\"\n}\n\n.glyphicon-pawn:before {\n    content: \"\\e213\"\n}\n\n.glyphicon-bishop:before {\n    content: \"\\e214\"\n}\n\n.glyphicon-knight:before {\n    content: \"\\e215\"\n}\n\n.glyphicon-baby-formula:before {\n    content: \"\\e216\"\n}\n\n.glyphicon-tent:before {\n    content: \"\\26fa\"\n}\n\n.glyphicon-blackboard:before {\n    content: \"\\e218\"\n}\n\n.glyphicon-bed:before {\n    content: \"\\e219\"\n}\n\n.glyphicon-apple:before {\n    content: \"\\f8ff\"\n}\n\n.glyphicon-erase:before {\n    content: \"\\e221\"\n}\n\n.glyphicon-hourglass:before {\n    content: \"\\231b\"\n}\n\n.glyphicon-lamp:before {\n    content: \"\\e223\"\n}\n\n.glyphicon-duplicate:before {\n    content: \"\\e224\"\n}\n\n.glyphicon-piggy-bank:before {\n    content: \"\\e225\"\n}\n\n.glyphicon-scissors:before {\n    content: \"\\e226\"\n}\n\n.glyphicon-bitcoin:before, .glyphicon-btc:before, .glyphicon-xbt:before {\n    content: \"\\e227\"\n}\n\n.glyphicon-jpy:before, .glyphicon-yen:before {\n    content: \"\\00a5\"\n}\n\n.glyphicon-rub:before, .glyphicon-ruble:before {\n    content: \"\\20bd\"\n}\n\n.glyphicon-scale:before {\n    content: \"\\e230\"\n}\n\n.glyphicon-ice-lolly:before {\n    content: \"\\e231\"\n}\n\n.glyphicon-ice-lolly-tasted:before {\n    content: \"\\e232\"\n}\n\n.glyphicon-education:before {\n    content: \"\\e233\"\n}\n\n.glyphicon-option-horizontal:before {\n    content: \"\\e234\"\n}\n\n.glyphicon-option-vertical:before {\n    content: \"\\e235\"\n}\n\n.glyphicon-menu-hamburger:before {\n    content: \"\\e236\"\n}\n\n.glyphicon-modal-window:before {\n    content: \"\\e237\"\n}\n\n.glyphicon-oil:before {\n    content: \"\\e238\"\n}\n\n.glyphicon-grain:before {\n    content: \"\\e239\"\n}\n\n.glyphicon-sunglasses:before {\n    content: \"\\e240\"\n}\n\n.glyphicon-text-size:before {\n    content: \"\\e241\"\n}\n\n.glyphicon-text-color:before {\n    content: \"\\e242\"\n}\n\n.glyphicon-text-background:before {\n    content: \"\\e243\"\n}\n\n.glyphicon-object-align-top:before {\n    content: \"\\e244\"\n}\n\n.glyphicon-object-align-bottom:before {\n    content: \"\\e245\"\n}\n\n.glyphicon-object-align-horizontal:before {\n    content: \"\\e246\"\n}\n\n.glyphicon-object-align-left:before {\n    content: \"\\e247\"\n}\n\n.glyphicon-object-align-vertical:before {\n    content: \"\\e248\"\n}\n\n.glyphicon-object-align-right:before {\n    content: \"\\e249\"\n}\n\n.glyphicon-triangle-right:before {\n    content: \"\\e250\"\n}\n\n.glyphicon-triangle-left:before {\n    content: \"\\e251\"\n}\n\n.glyphicon-triangle-bottom:before {\n    content: \"\\e252\"\n}\n\n.glyphicon-triangle-top:before {\n    content: \"\\e253\"\n}\n\n.glyphicon-console:before {\n    content: \"\\e254\"\n}\n\n.glyphicon-superscript:before {\n    content: \"\\e255\"\n}\n\n.glyphicon-subscript:before {\n    content: \"\\e256\"\n}\n\n.glyphicon-menu-left:before {\n    content: \"\\e257\"\n}\n\n.glyphicon-menu-right:before {\n    content: \"\\e258\"\n}\n\n.glyphicon-menu-down:before {\n    content: \"\\e259\"\n}\n\n.glyphicon-menu-up:before {\n    content: \"\\e260\"\n}\n\n*, :after, :before {\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box\n}\n\nhtml {\n    font-size: 10px;\n    -webkit-tap-highlight-color: transparent\n}\n\n\nbutton, input, select, textarea {\n    font-family: inherit;\n    font-size: inherit;\n    line-height: inherit\n}\n\na {\n    background-color: transparent;\n    color: #337ab7;\n    text-decoration: none\n}\n\n    a:focus, a:hover {\n        color: #23527c;\n        text-decoration: underline\n    }\n\n    a:focus {\n        outline: -webkit-focus-ring-color auto 5px;\n        outline-offset: -2px\n    }\n\nfigure {\n    margin: 0\n}\n\n.carousel-inner > .item > a > img, .carousel-inner > .item > img, .img-responsive, .thumbnail a > img, .thumbnail > img {\n    display: block;\n    max-width: 100%;\n    height: auto\n}\n\n.img-rounded {\n    border-radius: 6px\n}\n\n.img-thumbnail {\n    padding: 4px;\n    line-height: 1.42857143;\n    background-color: #fff;\n    border: 1px solid #ddd;\n    border-radius: 4px;\n    -webkit-transition: .2s ease-in-out;\n    -o-transition: .2s ease-in-out;\n    transition: .2s ease-in-out;\n    display: inline-block;\n    max-width: 100%;\n    height: auto\n}\n\n.img-circle {\n    border-radius: 50%\n}\n\nhr {\n    margin-top: 20px;\n    margin-bottom: 20px;\n    border: 0;\n    border-top: 1px solid #eee\n}\n\n.sr-only {\n    position: absolute;\n    width: 1px;\n    height: 1px;\n    padding: 0;\n    margin: -1px;\n    overflow: hidden;\n    clip: rect(0,0,0,0);\n    border: 0\n}\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n    position: static;\n    width: auto;\n    height: auto;\n    margin: 0;\n    overflow: visible;\n    clip: auto\n}\n\n[role=button] {\n    cursor: pointer\n}\n\n.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {\n    font-family: inherit;\n    font-weight: 500;\n    line-height: 1.1;\n    color: inherit\n}\n\n    .h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, .h4 .small, .h4 small, .h5 .small, .h5 small, .h6 .small, .h6 small, h1 .small, h1 small, h2 .small, h2 small, h3 .small, h3 small, h4 .small, h4 small, h5 .small, h5 small, h6 .small, h6 small {\n        font-weight: 400;\n        line-height: 1;\n        color: #777\n    }\n\n.h1, .h2, .h3, h1, h2, h3 {\n    margin-top: 20px;\n    margin-bottom: 10px\n}\n\n    .h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, h1 .small, h1 small, h2 .small, h2 small, h3 .small, h3 small {\n        font-size: 65%\n    }\n\n.h4, .h5, .h6, h4, h5, h6 {\n    margin-top: 10px;\n    margin-bottom: 10px\n}\n\n    .h4 .small, .h4 small, .h5 .small, .h5 small, .h6 .small, .h6 small, h4 .small, h4 small, h5 .small, h5 small, h6 .small, h6 small {\n        font-size: 75%\n    }\n\n.h1, h1 {\n    font-size: 36px\n}\n\n.h2, h2 {\n    font-size: 30px\n}\n\n.h3, h3 {\n    font-size: 24px\n}\n\n.h4, h4 {\n    font-size: 18px\n}\n\n.h5, h5 {\n    font-size: 14px\n}\n\n.h6, h6 {\n    font-size: 12px\n}\n\np {\n    margin: 0 0 10px\n}\n\n.lead {\n    margin-bottom: 20px;\n    font-size: 16px;\n    font-weight: 300;\n    line-height: 1.4\n}\n\n@media (min-width:768px) {\n    .lead {\n        font-size: 21px\n    }\n\n    .dl-horizontal dt {\n        float: left;\n        width: 160px;\n        clear: left;\n        text-align: right;\n        overflow: hidden;\n        text-overflow: ellipsis;\n        white-space: nowrap\n    }\n\n    .dl-horizontal dd {\n        margin-left: 180px\n    }\n}\n\n.small, small {\n    font-size: 85%\n}\n\n.mark, mark {\n    padding: .2em;\n    background-color: #fcf8e3\n}\n\n.text-left {\n    text-align: left\n}\n\n.text-right {\n    text-align: right\n}\n\n.text-center {\n    text-align: center\n}\n\n.text-justify {\n    text-align: justify\n}\n\n.text-nowrap {\n    white-space: nowrap\n}\n\n.text-lowercase {\n    text-transform: lowercase\n}\n\n.text-uppercase {\n    text-transform: uppercase\n}\n\n.text-capitalize {\n    text-transform: capitalize\n}\n\n.text-muted {\n    color: #777\n}\n\n.text-primary {\n    color: #337ab7\n}\n\na.text-primary:focus, a.text-primary:hover {\n    color: #286090\n}\n\n.text-success {\n    color: #3c763d\n}\n\na.text-success:focus, a.text-success:hover {\n    color: #2b542c\n}\n\n.text-info {\n    color: #31708f\n}\n\na.text-info:focus, a.text-info:hover {\n    color: #245269\n}\n\n.text-warning {\n    color: #8a6d3b\n}\n\na.text-warning:focus, a.text-warning:hover {\n    color: #66512c\n}\n\n.text-danger {\n    color: #a94442\n}\n\na.text-danger:focus, a.text-danger:hover {\n    color: #843534\n}\n\n.bg-primary {\n    color: #fff;\n    background-color: #337ab7\n}\n\na.bg-primary:focus, a.bg-primary:hover {\n    background-color: #286090\n}\n\n.bg-success {\n    background-color: #dff0d8\n}\n\na.bg-success:focus, a.bg-success:hover {\n    background-color: #c1e2b3\n}\n\n.bg-info {\n    background-color: #d9edf7\n}\n\na.bg-info:focus, a.bg-info:hover {\n    background-color: #afd9ee\n}\n\n.bg-warning {\n    background-color: #fcf8e3\n}\n\na.bg-warning:focus, a.bg-warning:hover {\n    background-color: #f7ecb5\n}\n\n.bg-danger {\n    background-color: #f2dede\n}\n\na.bg-danger:focus, a.bg-danger:hover {\n    background-color: #e4b9b9\n}\n\n.page-header {\n    padding-bottom: 9px;\n    margin: 40px 0 20px;\n    border-bottom: 1px solid #eee\n}\n\nol, ul {\n    margin-top: 0;\n    margin-bottom: 10px\n}\n\n    ol ol, ol ul, ul ol, ul ul {\n        margin-bottom: 0\n    }\n\n.list-unstyled {\n    padding-left: 0;\n    list-style: none\n}\n\n.list-inline {\n    padding-left: 0;\n    list-style: none;\n    margin-left: -5px\n}\n\n    .list-inline > li {\n        display: inline-block;\n        padding-right: 5px;\n        padding-left: 5px\n    }\n\ndl {\n    margin-top: 0;\n    margin-bottom: 20px\n}\n\ndd, dt {\n    line-height: 1.42857143\n}\n\ndt {\n    font-weight: 700\n}\n\ndd {\n    margin-left: 0\n}\n\nabbr[data-original-title], abbr[title] {\n    cursor: help\n}\n\n.initialism {\n    font-size: 90%;\n    text-transform: uppercase\n}\n\nblockquote {\n    padding: 10px 20px;\n    margin: 0 0 20px;\n    font-size: 17.5px;\n    border-left: 5px solid #eee\n}\n\n    blockquote ol:last-child, blockquote p:last-child, blockquote ul:last-child {\n        margin-bottom: 0\n    }\n\n    blockquote .small, blockquote footer, blockquote small {\n        display: block;\n        font-size: 80%;\n        line-height: 1.42857143;\n        color: #777\n    }\n\n        blockquote .small:before, blockquote footer:before, blockquote small:before {\n            content: \"\\2014 \\00A0\"\n        }\n\n    .blockquote-reverse, blockquote.pull-right {\n        padding-right: 15px;\n        padding-left: 0;\n        text-align: right;\n        border-right: 5px solid #eee;\n        border-left: 0\n    }\n\n        .blockquote-reverse .small:before, .blockquote-reverse footer:before, .blockquote-reverse small:before, blockquote.pull-right .small:before, blockquote.pull-right footer:before, blockquote.pull-right small:before {\n            content: \"\"\n        }\n\n        .blockquote-reverse .small:after, .blockquote-reverse footer:after, .blockquote-reverse small:after, blockquote.pull-right .small:after, blockquote.pull-right footer:after, blockquote.pull-right small:after {\n            content: \"\\00A0 \\2014\"\n        }\n\naddress {\n    margin-bottom: 20px;\n    font-style: normal;\n    line-height: 1.42857143\n}\n\ncode, kbd, pre, samp {\n    font-family: Menlo,Monaco,Consolas,\"Courier New\",monospace\n}\n\ncode {\n    padding: 2px 4px;\n    font-size: 90%;\n    color: #c7254e;\n    background-color: #f9f2f4;\n    border-radius: 4px\n}\n\nkbd {\n    padding: 2px 4px;\n    font-size: 90%;\n    color: #fff;\n    background-color: #333;\n    border-radius: 3px;\n    -webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n    box-shadow: inset 0 -1px 0 rgba(0,0,0,.25)\n}\n\n    kbd kbd {\n        padding: 0;\n        font-size: 100%;\n        font-weight: 700;\n        -webkit-box-shadow: none;\n        box-shadow: none\n    }\n\npre {\n    overflow: auto;\n    display: block;\n    padding: 9.5px;\n    margin: 0 0 10px;\n    font-size: 13px;\n    line-height: 1.42857143;\n    color: #333;\n    word-break: break-all;\n    word-wrap: break-word;\n    background-color: #f5f5f5;\n    border: 1px solid #ccc;\n    border-radius: 4px\n}\n\n    pre code {\n        padding: 0;\n        font-size: inherit;\n        color: inherit;\n        white-space: pre-wrap;\n        background-color: transparent;\n        border-radius: 0\n    }\n\n.pre-scrollable {\n    max-height: 340px;\n    overflow-y: scroll\n}\n\n.container {\n    padding-right: 15px;\n    padding-left: 15px;\n    margin-right: auto;\n    margin-left: auto\n}\n\n@media (min-width:768px) {\n    .container {\n        width: 750px\n    }\n}\n\n@media (min-width:992px) {\n    .container {\n        width: 970px\n    }\n}\n\n@media (min-width:1200px) {\n    .container {\n        width: 1170px\n    }\n}\n\n.container-fluid {\n    padding-right: 15px;\n    padding-left: 15px;\n    margin-right: auto;\n    margin-left: auto\n}\n\n.row {\n    margin-right: -15px;\n    margin-left: -15px\n}\n\n.row-no-gutters {\n    margin-right: 0;\n    margin-left: 0\n}\n\n    .row-no-gutters [class*=col-] {\n        padding-right: 0;\n        padding-left: 0\n    }\n\n.col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 {\n    position: relative;\n    min-height: 1px;\n    padding-right: 15px;\n    padding-left: 15px\n}\n\n.col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 {\n    float: left\n}\n\n.col-xs-12 {\n    width: 100%\n}\n\n.col-xs-11 {\n    width: 91.66666667%\n}\n\n.col-xs-10 {\n    width: 83.33333333%\n}\n\n.col-xs-9 {\n    width: 75%\n}\n\n.col-xs-8 {\n    width: 66.66666667%\n}\n\n.col-xs-7 {\n    width: 58.33333333%\n}\n\n.col-xs-6 {\n    width: 50%\n}\n\n.col-xs-5 {\n    width: 41.66666667%\n}\n\n.col-xs-4 {\n    width: 33.33333333%\n}\n\n.col-xs-3 {\n    width: 25%\n}\n\n.col-xs-2 {\n    width: 16.66666667%\n}\n\n.col-xs-1 {\n    width: 8.33333333%\n}\n\n.col-xs-pull-12 {\n    right: 100%\n}\n\n.col-xs-pull-11 {\n    right: 91.66666667%\n}\n\n.col-xs-pull-10 {\n    right: 83.33333333%\n}\n\n.col-xs-pull-9 {\n    right: 75%\n}\n\n.col-xs-pull-8 {\n    right: 66.66666667%\n}\n\n.col-xs-pull-7 {\n    right: 58.33333333%\n}\n\n.col-xs-pull-6 {\n    right: 50%\n}\n\n.col-xs-pull-5 {\n    right: 41.66666667%\n}\n\n.col-xs-pull-4 {\n    right: 33.33333333%\n}\n\n.col-xs-pull-3 {\n    right: 25%\n}\n\n.col-xs-pull-2 {\n    right: 16.66666667%\n}\n\n.col-xs-pull-1 {\n    right: 8.33333333%\n}\n\n.col-xs-pull-0 {\n    right: auto\n}\n\n.col-xs-push-12 {\n    left: 100%\n}\n\n.col-xs-push-11 {\n    left: 91.66666667%\n}\n\n.col-xs-push-10 {\n    left: 83.33333333%\n}\n\n.col-xs-push-9 {\n    left: 75%\n}\n\n.col-xs-push-8 {\n    left: 66.66666667%\n}\n\n.col-xs-push-7 {\n    left: 58.33333333%\n}\n\n.col-xs-push-6 {\n    left: 50%\n}\n\n.col-xs-push-5 {\n    left: 41.66666667%\n}\n\n.col-xs-push-4 {\n    left: 33.33333333%\n}\n\n.col-xs-push-3 {\n    left: 25%\n}\n\n.col-xs-push-2 {\n    left: 16.66666667%\n}\n\n.col-xs-push-1 {\n    left: 8.33333333%\n}\n\n.col-xs-push-0 {\n    left: auto\n}\n\n.col-xs-offset-12 {\n    margin-left: 100%\n}\n\n.col-xs-offset-11 {\n    margin-left: 91.66666667%\n}\n\n.col-xs-offset-10 {\n    margin-left: 83.33333333%\n}\n\n.col-xs-offset-9 {\n    margin-left: 75%\n}\n\n.col-xs-offset-8 {\n    margin-left: 66.66666667%\n}\n\n.col-xs-offset-7 {\n    margin-left: 58.33333333%\n}\n\n.col-xs-offset-6 {\n    margin-left: 50%\n}\n\n.col-xs-offset-5 {\n    margin-left: 41.66666667%\n}\n\n.col-xs-offset-4 {\n    margin-left: 33.33333333%\n}\n\n.col-xs-offset-3 {\n    margin-left: 25%\n}\n\n.col-xs-offset-2 {\n    margin-left: 16.66666667%\n}\n\n.col-xs-offset-1 {\n    margin-left: 8.33333333%\n}\n\n.col-xs-offset-0 {\n    margin-left: 0\n}\n\n@media (min-width:768px) {\n    .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9 {\n        float: left\n    }\n\n    .col-sm-12 {\n        width: 100%\n    }\n\n    .col-sm-11 {\n        width: 91.66666667%\n    }\n\n    .col-sm-10 {\n        width: 83.33333333%\n    }\n\n    .col-sm-9 {\n        width: 75%\n    }\n\n    .col-sm-8 {\n        width: 66.66666667%\n    }\n\n    .col-sm-7 {\n        width: 58.33333333%\n    }\n\n    .col-sm-6 {\n        width: 50%\n    }\n\n    .col-sm-5 {\n        width: 41.66666667%\n    }\n\n    .col-sm-4 {\n        width: 33.33333333%\n    }\n\n    .col-sm-3 {\n        width: 25%\n    }\n\n    .col-sm-2 {\n        width: 16.66666667%\n    }\n\n    .col-sm-1 {\n        width: 8.33333333%\n    }\n\n    .col-sm-pull-12 {\n        right: 100%\n    }\n\n    .col-sm-pull-11 {\n        right: 91.66666667%\n    }\n\n    .col-sm-pull-10 {\n        right: 83.33333333%\n    }\n\n    .col-sm-pull-9 {\n        right: 75%\n    }\n\n    .col-sm-pull-8 {\n        right: 66.66666667%\n    }\n\n    .col-sm-pull-7 {\n        right: 58.33333333%\n    }\n\n    .col-sm-pull-6 {\n        right: 50%\n    }\n\n    .col-sm-pull-5 {\n        right: 41.66666667%\n    }\n\n    .col-sm-pull-4 {\n        right: 33.33333333%\n    }\n\n    .col-sm-pull-3 {\n        right: 25%\n    }\n\n    .col-sm-pull-2 {\n        right: 16.66666667%\n    }\n\n    .col-sm-pull-1 {\n        right: 8.33333333%\n    }\n\n    .col-sm-pull-0 {\n        right: auto\n    }\n\n    .col-sm-push-12 {\n        left: 100%\n    }\n\n    .col-sm-push-11 {\n        left: 91.66666667%\n    }\n\n    .col-sm-push-10 {\n        left: 83.33333333%\n    }\n\n    .col-sm-push-9 {\n        left: 75%\n    }\n\n    .col-sm-push-8 {\n        left: 66.66666667%\n    }\n\n    .col-sm-push-7 {\n        left: 58.33333333%\n    }\n\n    .col-sm-push-6 {\n        left: 50%\n    }\n\n    .col-sm-push-5 {\n        left: 41.66666667%\n    }\n\n    .col-sm-push-4 {\n        left: 33.33333333%\n    }\n\n    .col-sm-push-3 {\n        left: 25%\n    }\n\n    .col-sm-push-2 {\n        left: 16.66666667%\n    }\n\n    .col-sm-push-1 {\n        left: 8.33333333%\n    }\n\n    .col-sm-push-0 {\n        left: auto\n    }\n\n    .col-sm-offset-12 {\n        margin-left: 100%\n    }\n\n    .col-sm-offset-11 {\n        margin-left: 91.66666667%\n    }\n\n    .col-sm-offset-10 {\n        margin-left: 83.33333333%\n    }\n\n    .col-sm-offset-9 {\n        margin-left: 75%\n    }\n\n    .col-sm-offset-8 {\n        margin-left: 66.66666667%\n    }\n\n    .col-sm-offset-7 {\n        margin-left: 58.33333333%\n    }\n\n    .col-sm-offset-6 {\n        margin-left: 50%\n    }\n\n    .col-sm-offset-5 {\n        margin-left: 41.66666667%\n    }\n\n    .col-sm-offset-4 {\n        margin-left: 33.33333333%\n    }\n\n    .col-sm-offset-3 {\n        margin-left: 25%\n    }\n\n    .col-sm-offset-2 {\n        margin-left: 16.66666667%\n    }\n\n    .col-sm-offset-1 {\n        margin-left: 8.33333333%\n    }\n\n    .col-sm-offset-0 {\n        margin-left: 0\n    }\n}\n\n@media (min-width:992px) {\n    .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9 {\n        float: left\n    }\n\n    .col-md-12 {\n        width: 100%\n    }\n\n    .col-md-11 {\n        width: 91.66666667%\n    }\n\n    .col-md-10 {\n        width: 83.33333333%\n    }\n\n    .col-md-9 {\n        width: 75%\n    }\n\n    .col-md-8 {\n        width: 66.66666667%\n    }\n\n    .col-md-7 {\n        width: 58.33333333%\n    }\n\n    .col-md-6 {\n        width: 50%\n    }\n\n    .col-md-5 {\n        width: 41.66666667%\n    }\n\n    .col-md-4 {\n        width: 33.33333333%\n    }\n\n    .col-md-3 {\n        width: 25%\n    }\n\n    .col-md-2 {\n        width: 16.66666667%\n    }\n\n    .col-md-1 {\n        width: 8.33333333%\n    }\n\n    .col-md-pull-12 {\n        right: 100%\n    }\n\n    .col-md-pull-11 {\n        right: 91.66666667%\n    }\n\n    .col-md-pull-10 {\n        right: 83.33333333%\n    }\n\n    .col-md-pull-9 {\n        right: 75%\n    }\n\n    .col-md-pull-8 {\n        right: 66.66666667%\n    }\n\n    .col-md-pull-7 {\n        right: 58.33333333%\n    }\n\n    .col-md-pull-6 {\n        right: 50%\n    }\n\n    .col-md-pull-5 {\n        right: 41.66666667%\n    }\n\n    .col-md-pull-4 {\n        right: 33.33333333%\n    }\n\n    .col-md-pull-3 {\n        right: 25%\n    }\n\n    .col-md-pull-2 {\n        right: 16.66666667%\n    }\n\n    .col-md-pull-1 {\n        right: 8.33333333%\n    }\n\n    .col-md-pull-0 {\n        right: auto\n    }\n\n    .col-md-push-12 {\n        left: 100%\n    }\n\n    .col-md-push-11 {\n        left: 91.66666667%\n    }\n\n    .col-md-push-10 {\n        left: 83.33333333%\n    }\n\n    .col-md-push-9 {\n        left: 75%\n    }\n\n    .col-md-push-8 {\n        left: 66.66666667%\n    }\n\n    .col-md-push-7 {\n        left: 58.33333333%\n    }\n\n    .col-md-push-6 {\n        left: 50%\n    }\n\n    .col-md-push-5 {\n        left: 41.66666667%\n    }\n\n    .col-md-push-4 {\n        left: 33.33333333%\n    }\n\n    .col-md-push-3 {\n        left: 25%\n    }\n\n    .col-md-push-2 {\n        left: 16.66666667%\n    }\n\n    .col-md-push-1 {\n        left: 8.33333333%\n    }\n\n    .col-md-push-0 {\n        left: auto\n    }\n\n    .col-md-offset-12 {\n        margin-left: 100%\n    }\n\n    .col-md-offset-11 {\n        margin-left: 91.66666667%\n    }\n\n    .col-md-offset-10 {\n        margin-left: 83.33333333%\n    }\n\n    .col-md-offset-9 {\n        margin-left: 75%\n    }\n\n    .col-md-offset-8 {\n        margin-left: 66.66666667%\n    }\n\n    .col-md-offset-7 {\n        margin-left: 58.33333333%\n    }\n\n    .col-md-offset-6 {\n        margin-left: 50%\n    }\n\n    .col-md-offset-5 {\n        margin-left: 41.66666667%\n    }\n\n    .col-md-offset-4 {\n        margin-left: 33.33333333%\n    }\n\n    .col-md-offset-3 {\n        margin-left: 25%\n    }\n\n    .col-md-offset-2 {\n        margin-left: 16.66666667%\n    }\n\n    .col-md-offset-1 {\n        margin-left: 8.33333333%\n    }\n\n    .col-md-offset-0 {\n        margin-left: 0\n    }\n}\n\n@media (min-width:1200px) {\n    .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9 {\n        float: left\n    }\n\n    .col-lg-12 {\n        width: 100%\n    }\n\n    .col-lg-11 {\n        width: 91.66666667%\n    }\n\n    .col-lg-10 {\n        width: 83.33333333%\n    }\n\n    .col-lg-9 {\n        width: 75%\n    }\n\n    .col-lg-8 {\n        width: 66.66666667%\n    }\n\n    .col-lg-7 {\n        width: 58.33333333%\n    }\n\n    .col-lg-6 {\n        width: 50%\n    }\n\n    .col-lg-5 {\n        width: 41.66666667%\n    }\n\n    .col-lg-4 {\n        width: 33.33333333%\n    }\n\n    .col-lg-3 {\n        width: 25%\n    }\n\n    .col-lg-2 {\n        width: 16.66666667%\n    }\n\n    .col-lg-1 {\n        width: 8.33333333%\n    }\n\n    .col-lg-pull-12 {\n        right: 100%\n    }\n\n    .col-lg-pull-11 {\n        right: 91.66666667%\n    }\n\n    .col-lg-pull-10 {\n        right: 83.33333333%\n    }\n\n    .col-lg-pull-9 {\n        right: 75%\n    }\n\n    .col-lg-pull-8 {\n        right: 66.66666667%\n    }\n\n    .col-lg-pull-7 {\n        right: 58.33333333%\n    }\n\n    .col-lg-pull-6 {\n        right: 50%\n    }\n\n    .col-lg-pull-5 {\n        right: 41.66666667%\n    }\n\n    .col-lg-pull-4 {\n        right: 33.33333333%\n    }\n\n    .col-lg-pull-3 {\n        right: 25%\n    }\n\n    .col-lg-pull-2 {\n        right: 16.66666667%\n    }\n\n    .col-lg-pull-1 {\n        right: 8.33333333%\n    }\n\n    .col-lg-pull-0 {\n        right: auto\n    }\n\n    .col-lg-push-12 {\n        left: 100%\n    }\n\n    .col-lg-push-11 {\n        left: 91.66666667%\n    }\n\n    .col-lg-push-10 {\n        left: 83.33333333%\n    }\n\n    .col-lg-push-9 {\n        left: 75%\n    }\n\n    .col-lg-push-8 {\n        left: 66.66666667%\n    }\n\n    .col-lg-push-7 {\n        left: 58.33333333%\n    }\n\n    .col-lg-push-6 {\n        left: 50%\n    }\n\n    .col-lg-push-5 {\n        left: 41.66666667%\n    }\n\n    .col-lg-push-4 {\n        left: 33.33333333%\n    }\n\n    .col-lg-push-3 {\n        left: 25%\n    }\n\n    .col-lg-push-2 {\n        left: 16.66666667%\n    }\n\n    .col-lg-push-1 {\n        left: 8.33333333%\n    }\n\n    .col-lg-push-0 {\n        left: auto\n    }\n\n    .col-lg-offset-12 {\n        margin-left: 100%\n    }\n\n    .col-lg-offset-11 {\n        margin-left: 91.66666667%\n    }\n\n    .col-lg-offset-10 {\n        margin-left: 83.33333333%\n    }\n\n    .col-lg-offset-9 {\n        margin-left: 75%\n    }\n\n    .col-lg-offset-8 {\n        margin-left: 66.66666667%\n    }\n\n    .col-lg-offset-7 {\n        margin-left: 58.33333333%\n    }\n\n    .col-lg-offset-6 {\n        margin-left: 50%\n    }\n\n    .col-lg-offset-5 {\n        margin-left: 41.66666667%\n    }\n\n    .col-lg-offset-4 {\n        margin-left: 33.33333333%\n    }\n\n    .col-lg-offset-3 {\n        margin-left: 25%\n    }\n\n    .col-lg-offset-2 {\n        margin-left: 16.66666667%\n    }\n\n    .col-lg-offset-1 {\n        margin-left: 8.33333333%\n    }\n\n    .col-lg-offset-0 {\n        margin-left: 0\n    }\n}\n\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n    background-color: transparent\n}\n\n    table col[class*=col-] {\n        position: static;\n        display: table-column;\n        float: none\n    }\n\n    table td[class*=col-], table th[class*=col-] {\n        position: static;\n        display: table-cell;\n        float: none\n    }\n\ncaption {\n    padding-top: 8px;\n    padding-bottom: 8px;\n    color: #777;\n    text-align: left\n}\n\nth {\n    text-align: left\n}\n\n.table {\n    width: 100%;\n    max-width: 100%;\n    margin-bottom: 20px\n}\n\n    .table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th {\n        padding: 8px;\n        line-height: 1.42857143;\n        vertical-align: top;\n        border-top: 1px solid #ddd\n    }\n\n    .table > thead > tr > th {\n        vertical-align: bottom;\n        border-bottom: 2px solid #ddd\n    }\n\n    .table > caption + thead > tr:first-child > td, .table > caption + thead > tr:first-child > th, .table > colgroup + thead > tr:first-child > td, .table > colgroup + thead > tr:first-child > th, .table > thead:first-child > tr:first-child > td, .table > thead:first-child > tr:first-child > th {\n        border-top: 0\n    }\n\n    .table > tbody + tbody {\n        border-top: 2px solid #ddd\n    }\n\n    .table .table {\n        background-color: #fff\n    }\n\n.table-condensed > tbody > tr > td, .table-condensed > tbody > tr > th, .table-condensed > tfoot > tr > td, .table-condensed > tfoot > tr > th, .table-condensed > thead > tr > td, .table-condensed > thead > tr > th {\n    padding: 5px\n}\n\n.table-bordered, .table-bordered > tbody > tr > td, .table-bordered > tbody > tr > th, .table-bordered > tfoot > tr > td, .table-bordered > tfoot > tr > th, .table-bordered > thead > tr > td, .table-bordered > thead > tr > th {\n    border: 1px solid #ddd\n}\n\n    .table-bordered > thead > tr > td, .table-bordered > thead > tr > th {\n        border-bottom-width: 2px\n    }\n\n.table-striped > tbody > tr:nth-of-type(odd) {\n    background-color: #f9f9f9\n}\n\n.table-hover > tbody > tr:hover, .table > tbody > tr.active > td, .table > tbody > tr.active > th, .table > tbody > tr > td.active, .table > tbody > tr > th.active, .table > tfoot > tr.active > td, .table > tfoot > tr.active > th, .table > tfoot > tr > td.active, .table > tfoot > tr > th.active, .table > thead > tr.active > td, .table > thead > tr.active > th, .table > thead > tr > td.active, .table > thead > tr > th.active {\n    background-color: #f5f5f5\n}\n\n    .table-hover > tbody > tr.active:hover > td, .table-hover > tbody > tr.active:hover > th, .table-hover > tbody > tr:hover > .active, .table-hover > tbody > tr > td.active:hover, .table-hover > tbody > tr > th.active:hover {\n        background-color: #e8e8e8\n    }\n\n.table > tbody > tr.success > td, .table > tbody > tr.success > th, .table > tbody > tr > td.success, .table > tbody > tr > th.success, .table > tfoot > tr.success > td, .table > tfoot > tr.success > th, .table > tfoot > tr > td.success, .table > tfoot > tr > th.success, .table > thead > tr.success > td, .table > thead > tr.success > th, .table > thead > tr > td.success, .table > thead > tr > th.success {\n    background-color: #dff0d8\n}\n\n.table-hover > tbody > tr.success:hover > td, .table-hover > tbody > tr.success:hover > th, .table-hover > tbody > tr:hover > .success, .table-hover > tbody > tr > td.success:hover, .table-hover > tbody > tr > th.success:hover {\n    background-color: #d0e9c6\n}\n\n.table > tbody > tr.info > td, .table > tbody > tr.info > th, .table > tbody > tr > td.info, .table > tbody > tr > th.info, .table > tfoot > tr.info > td, .table > tfoot > tr.info > th, .table > tfoot > tr > td.info, .table > tfoot > tr > th.info, .table > thead > tr.info > td, .table > thead > tr.info > th, .table > thead > tr > td.info, .table > thead > tr > th.info {\n    background-color: #d9edf7\n}\n\n.table-hover > tbody > tr.info:hover > td, .table-hover > tbody > tr.info:hover > th, .table-hover > tbody > tr:hover > .info, .table-hover > tbody > tr > td.info:hover, .table-hover > tbody > tr > th.info:hover {\n    background-color: #c4e3f3\n}\n\n.table > tbody > tr.warning > td, .table > tbody > tr.warning > th, .table > tbody > tr > td.warning, .table > tbody > tr > th.warning, .table > tfoot > tr.warning > td, .table > tfoot > tr.warning > th, .table > tfoot > tr > td.warning, .table > tfoot > tr > th.warning, .table > thead > tr.warning > td, .table > thead > tr.warning > th, .table > thead > tr > td.warning, .table > thead > tr > th.warning {\n    background-color: #fcf8e3\n}\n\n.table-hover > tbody > tr.warning:hover > td, .table-hover > tbody > tr.warning:hover > th, .table-hover > tbody > tr:hover > .warning, .table-hover > tbody > tr > td.warning:hover, .table-hover > tbody > tr > th.warning:hover {\n    background-color: #faf2cc\n}\n\n.table > tbody > tr.danger > td, .table > tbody > tr.danger > th, .table > tbody > tr > td.danger, .table > tbody > tr > th.danger, .table > tfoot > tr.danger > td, .table > tfoot > tr.danger > th, .table > tfoot > tr > td.danger, .table > tfoot > tr > th.danger, .table > thead > tr.danger > td, .table > thead > tr.danger > th, .table > thead > tr > td.danger, .table > thead > tr > th.danger {\n    background-color: #f2dede\n}\n\n.table-hover > tbody > tr.danger:hover > td, .table-hover > tbody > tr.danger:hover > th, .table-hover > tbody > tr:hover > .danger, .table-hover > tbody > tr > td.danger:hover, .table-hover > tbody > tr > th.danger:hover {\n    background-color: #ebcccc\n}\n\n.table-responsive {\n    min-height: .01%;\n    overflow-x: auto\n}\n\n@media screen and (max-width:767px) {\n    .table-responsive {\n        width: 100%;\n        margin-bottom: 15px;\n        overflow-y: hidden;\n        -ms-overflow-style: -ms-autohiding-scrollbar;\n        border: 1px solid #ddd\n    }\n\n        .table-responsive > .table {\n            margin-bottom: 0\n        }\n\n            .table-responsive > .table > tbody > tr > td, .table-responsive > .table > tbody > tr > th, .table-responsive > .table > tfoot > tr > td, .table-responsive > .table > tfoot > tr > th, .table-responsive > .table > thead > tr > td, .table-responsive > .table > thead > tr > th {\n                white-space: nowrap\n            }\n\n        .table-responsive > .table-bordered {\n            border: 0\n        }\n\n            .table-responsive > .table-bordered > tbody > tr > td:first-child, .table-responsive > .table-bordered > tbody > tr > th:first-child, .table-responsive > .table-bordered > tfoot > tr > td:first-child, .table-responsive > .table-bordered > tfoot > tr > th:first-child, .table-responsive > .table-bordered > thead > tr > td:first-child, .table-responsive > .table-bordered > thead > tr > th:first-child {\n                border-left: 0\n            }\n\n            .table-responsive > .table-bordered > tbody > tr > td:last-child, .table-responsive > .table-bordered > tbody > tr > th:last-child, .table-responsive > .table-bordered > tfoot > tr > td:last-child, .table-responsive > .table-bordered > tfoot > tr > th:last-child, .table-responsive > .table-bordered > thead > tr > td:last-child, .table-responsive > .table-bordered > thead > tr > th:last-child {\n                border-right: 0\n            }\n\n            .table-responsive > .table-bordered > tbody > tr:last-child > td, .table-responsive > .table-bordered > tbody > tr:last-child > th, .table-responsive > .table-bordered > tfoot > tr:last-child > td, .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n                border-bottom: 0\n            }\n}\n\nfieldset {\n    min-width: 0;\n    padding: 0;\n    margin: 0;\n    border: 0\n}\n\nlegend {\n    display: block;\n    width: 100%;\n    padding: 0;\n    margin-bottom: 20px;\n    font-size: 21px;\n    line-height: inherit;\n    color: #333;\n    border: 0;\n    border-bottom: 1px solid #e5e5e5\n}\n\nlabel {\n    display: inline-block;\n    max-width: 100%;\n    margin-bottom: 5px;\n    font-weight: 700\n}\n\ninput[type=search] {\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n    -webkit-appearance: none;\n    -moz-appearance: none;\n    appearance: none\n}\n\ninput[type=checkbox], input[type=radio] {\n    margin: 4px 0 0;\n    line-height: normal\n}\n\n    fieldset[disabled] input[type=checkbox], fieldset[disabled] input[type=radio], input[type=checkbox].disabled, input[type=checkbox][disabled], input[type=radio].disabled, input[type=radio][disabled] {\n        cursor: not-allowed\n    }\n\ninput[type=file] {\n    display: block\n}\n\ninput[type=range] {\n    display: block;\n    width: 100%\n}\n\nselect[multiple], select[size] {\n    height: auto\n}\n\ninput[type=checkbox]:focus, input[type=file]:focus, input[type=radio]:focus {\n    outline: -webkit-focus-ring-color auto 5px;\n    outline-offset: -2px\n}\n\noutput {\n    display: block;\n    padding-top: 7px;\n    font-size: 14px;\n    line-height: 1.42857143;\n    color: #555\n}\n\n.form-control {\n    display: block;\n    width: 100%;\n    height: 34px;\n    padding: 6px 12px;\n    font-size: 14px;\n    line-height: 1.42857143;\n    color: #555;\n    background-color: #fff;\n    background-image: none;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);\n    box-shadow: inset 0 1px 1px rgba(0,0,0,.075);\n    -webkit-transition: border-color .15s ease-in-out,-webkit-box-shadow .15s ease-in-out;\n    -o-transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;\n    transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-box-shadow .15s ease-in-out\n}\n\n    .form-control:focus {\n        border-color: #66afe9;\n        outline: 0;\n        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);\n        box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)\n    }\n\n    .form-control::-moz-placeholder {\n        color: #999;\n        opacity: 1\n    }\n\n    .form-control:-ms-input-placeholder {\n        color: #999\n    }\n\n    .form-control::-webkit-input-placeholder {\n        color: #999\n    }\n\n    .form-control::-ms-expand {\n        background-color: transparent;\n        border: 0\n    }\n\n    .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {\n        background-color: #eee;\n        opacity: 1\n    }\n\n    .form-control[disabled], fieldset[disabled] .form-control {\n        cursor: not-allowed\n    }\n\ntextarea.form-control {\n    height: auto\n}\n\n@media screen and (-webkit-min-device-pixel-ratio:0) {\n    input[type=date].form-control, input[type=datetime-local].form-control, input[type=month].form-control, input[type=time].form-control {\n        line-height: 34px\n    }\n\n    .input-group-sm input[type=date], .input-group-sm input[type=datetime-local], .input-group-sm input[type=month], .input-group-sm input[type=time], input[type=date].input-sm, input[type=datetime-local].input-sm, input[type=month].input-sm, input[type=time].input-sm {\n        line-height: 30px\n    }\n\n    .input-group-lg input[type=date], .input-group-lg input[type=datetime-local], .input-group-lg input[type=month], .input-group-lg input[type=time], input[type=date].input-lg, input[type=datetime-local].input-lg, input[type=month].input-lg, input[type=time].input-lg {\n        line-height: 46px\n    }\n}\n\n.form-group {\n    margin-bottom: 15px\n}\n\n.checkbox, .radio {\n    position: relative;\n    display: block;\n    margin-top: 10px;\n    margin-bottom: 10px\n}\n\n    .checkbox.disabled label, .radio.disabled label, fieldset[disabled] .checkbox label, fieldset[disabled] .radio label {\n        cursor: not-allowed\n    }\n\n    .checkbox label, .radio label {\n        min-height: 20px;\n        padding-left: 20px;\n        margin-bottom: 0;\n        font-weight: 400;\n        cursor: pointer\n    }\n\n    .checkbox input[type=checkbox], .checkbox-inline input[type=checkbox], .radio input[type=radio], .radio-inline input[type=radio] {\n        position: absolute;\n        margin-left: -20px\n    }\n\n    .checkbox + .checkbox, .radio + .radio {\n        margin-top: -5px\n    }\n\n.checkbox-inline, .radio-inline {\n    position: relative;\n    display: inline-block;\n    padding-left: 20px;\n    margin-bottom: 0;\n    font-weight: 400;\n    vertical-align: middle;\n    cursor: pointer\n}\n\n    .checkbox-inline.disabled, .radio-inline.disabled, fieldset[disabled] .checkbox-inline, fieldset[disabled] .radio-inline {\n        cursor: not-allowed\n    }\n\n    .checkbox-inline + .checkbox-inline, .radio-inline + .radio-inline {\n        margin-top: 0;\n        margin-left: 10px\n    }\n\n.form-control-static {\n    min-height: 34px;\n    padding-top: 7px;\n    padding-bottom: 7px;\n    margin-bottom: 0\n}\n\n    .form-control-static.input-lg, .form-control-static.input-sm {\n        padding-right: 0;\n        padding-left: 0\n    }\n\n.input-sm {\n    height: 30px;\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px\n}\n\nselect.input-sm {\n    height: 30px;\n    line-height: 30px\n}\n\nselect[multiple].input-sm, textarea.input-sm {\n    height: auto\n}\n\n.form-group-sm .form-control {\n    height: 30px;\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px\n}\n\n.form-group-sm select.form-control {\n    height: 30px;\n    line-height: 30px\n}\n\n.form-group-sm select[multiple].form-control, .form-group-sm textarea.form-control {\n    height: auto\n}\n\n.form-group-sm .form-control-static {\n    height: 30px;\n    min-height: 32px;\n    padding: 6px 10px;\n    font-size: 12px;\n    line-height: 1.5\n}\n\n.input-lg {\n    height: 46px;\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 6px\n}\n\nselect.input-lg {\n    height: 46px;\n    line-height: 46px\n}\n\nselect[multiple].input-lg, textarea.input-lg {\n    height: auto\n}\n\n.form-group-lg .form-control {\n    height: 46px;\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 6px\n}\n\n.form-group-lg select.form-control {\n    height: 46px;\n    line-height: 46px\n}\n\n.form-group-lg select[multiple].form-control, .form-group-lg textarea.form-control {\n    height: auto\n}\n\n.form-group-lg .form-control-static {\n    height: 46px;\n    min-height: 38px;\n    padding: 11px 16px;\n    font-size: 18px;\n    line-height: 1.3333333\n}\n\n.has-feedback {\n    position: relative\n}\n\n    .has-feedback .form-control {\n        padding-right: 42.5px\n    }\n\n.form-control-feedback {\n    position: absolute;\n    top: 0;\n    right: 0;\n    z-index: 2;\n    display: block;\n    width: 34px;\n    height: 34px;\n    line-height: 34px;\n    text-align: center;\n    pointer-events: none\n}\n\n.form-group-lg .form-control + .form-control-feedback, .input-group-lg + .form-control-feedback, .input-lg + .form-control-feedback {\n    width: 46px;\n    height: 46px;\n    line-height: 46px\n}\n\n.form-group-sm .form-control + .form-control-feedback, .input-group-sm + .form-control-feedback, .input-sm + .form-control-feedback {\n    width: 30px;\n    height: 30px;\n    line-height: 30px\n}\n\n.has-success .checkbox, .has-success .checkbox-inline, .has-success .control-label, .has-success .help-block, .has-success .radio, .has-success .radio-inline, .has-success.checkbox label, .has-success.checkbox-inline label, .has-success.radio label, .has-success.radio-inline label {\n    color: #3c763d\n}\n\n.has-success .form-control {\n    border-color: #3c763d;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);\n    box-shadow: inset 0 1px 1px rgba(0,0,0,.075)\n}\n\n    .has-success .form-control:focus {\n        border-color: #2b542c;\n        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;\n        box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168\n    }\n\n.has-success .input-group-addon {\n    color: #3c763d;\n    background-color: #dff0d8;\n    border-color: #3c763d\n}\n\n.has-success .form-control-feedback {\n    color: #3c763d\n}\n\n.has-warning .checkbox, .has-warning .checkbox-inline, .has-warning .control-label, .has-warning .help-block, .has-warning .radio, .has-warning .radio-inline, .has-warning.checkbox label, .has-warning.checkbox-inline label, .has-warning.radio label, .has-warning.radio-inline label {\n    color: #8a6d3b\n}\n\n.has-warning .form-control {\n    border-color: #8a6d3b;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);\n    box-shadow: inset 0 1px 1px rgba(0,0,0,.075)\n}\n\n    .has-warning .form-control:focus {\n        border-color: #66512c;\n        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;\n        box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b\n    }\n\n.has-warning .input-group-addon {\n    color: #8a6d3b;\n    background-color: #fcf8e3;\n    border-color: #8a6d3b\n}\n\n.has-warning .form-control-feedback {\n    color: #8a6d3b\n}\n\n.has-error .checkbox, .has-error .checkbox-inline, .has-error .control-label, .has-error .help-block, .has-error .radio, .has-error .radio-inline, .has-error.checkbox label, .has-error.checkbox-inline label, .has-error.radio label, .has-error.radio-inline label {\n    color: #a94442\n}\n\n.has-error .form-control {\n    border-color: #a94442;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);\n    box-shadow: inset 0 1px 1px rgba(0,0,0,.075)\n}\n\n    .has-error .form-control:focus {\n        border-color: #843534;\n        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;\n        box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483\n    }\n\n.has-error .input-group-addon {\n    color: #a94442;\n    background-color: #f2dede;\n    border-color: #a94442\n}\n\n.has-error .form-control-feedback {\n    color: #a94442\n}\n\n.has-feedback label ~ .form-control-feedback {\n    top: 25px\n}\n\n.has-feedback label.sr-only ~ .form-control-feedback {\n    top: 0\n}\n\n.help-block {\n    display: block;\n    margin-top: 5px;\n    margin-bottom: 10px;\n    color: #737373\n}\n\n.form-horizontal .checkbox, .form-horizontal .checkbox-inline, .form-horizontal .radio, .form-horizontal .radio-inline {\n    padding-top: 7px;\n    margin-top: 0;\n    margin-bottom: 0\n}\n\n.form-horizontal .checkbox, .form-horizontal .radio {\n    min-height: 27px\n}\n\n.form-horizontal .form-group {\n    margin-right: -15px;\n    margin-left: -15px\n}\n\n.form-horizontal .has-feedback .form-control-feedback {\n    right: 15px\n}\n\n@media (min-width:768px) {\n    .form-inline .form-group {\n        display: inline-block;\n        margin-bottom: 0;\n        vertical-align: middle\n    }\n\n    .form-inline .form-control {\n        display: inline-block;\n        width: auto;\n        vertical-align: middle\n    }\n\n    .form-inline .form-control-static {\n        display: inline-block\n    }\n\n    .form-inline .input-group {\n        display: inline-table;\n        vertical-align: middle\n    }\n\n        .form-inline .input-group .form-control, .form-inline .input-group .input-group-addon, .form-inline .input-group .input-group-btn {\n            width: auto\n        }\n\n        .form-inline .input-group > .form-control {\n            width: 100%\n        }\n\n    .form-inline .control-label {\n        margin-bottom: 0;\n        vertical-align: middle\n    }\n\n    .form-inline .checkbox, .form-inline .radio {\n        display: inline-block;\n        margin-top: 0;\n        margin-bottom: 0;\n        vertical-align: middle\n    }\n\n        .form-inline .checkbox label, .form-inline .radio label {\n            padding-left: 0\n        }\n\n        .form-inline .checkbox input[type=checkbox], .form-inline .radio input[type=radio] {\n            position: relative;\n            margin-left: 0\n        }\n\n    .form-inline .has-feedback .form-control-feedback {\n        top: 0\n    }\n\n    .form-horizontal .control-label {\n        padding-top: 7px;\n        margin-bottom: 0;\n        text-align: right\n    }\n\n    .form-horizontal .form-group-lg .control-label {\n        padding-top: 11px;\n        font-size: 18px\n    }\n\n    .form-horizontal .form-group-sm .control-label {\n        padding-top: 6px;\n        font-size: 12px\n    }\n}\n\n.btn {\n    display: inline-block;\n    margin-bottom: 0;\n    font-weight: 400;\n    text-align: center;\n    white-space: nowrap;\n    vertical-align: middle;\n    -ms-touch-action: manipulation;\n    touch-action: manipulation;\n    cursor: pointer;\n    background-image: none;\n    border: 1px solid transparent;\n    padding: 6px 12px;\n    font-size: 14px;\n    line-height: 1.42857143;\n    border-radius: 4px;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none\n}\n\n    .btn.active.focus, .btn.active:focus, .btn.focus, .btn:active.focus, .btn:active:focus, .btn:focus {\n        outline: -webkit-focus-ring-color auto 5px;\n        outline-offset: -2px\n    }\n\n    .btn.focus, .btn:focus, .btn:hover {\n        color: #333;\n        text-decoration: none\n    }\n\n    .btn.active, .btn:active {\n        background-image: none;\n        outline: 0;\n        -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,.125);\n        box-shadow: inset 0 3px 5px rgba(0,0,0,.125)\n    }\n\n    .btn.disabled, .btn[disabled], fieldset[disabled] .btn {\n        cursor: not-allowed;\n        opacity: .65;\n        -webkit-box-shadow: none;\n        box-shadow: none\n    }\n\na.btn.disabled, fieldset[disabled] a.btn {\n    pointer-events: none\n}\n\n.btn-default {\n    color: #333;\n    background-color: #fff;\n    border-color: #ccc\n}\n\n    .btn-default.focus, .btn-default:focus {\n        color: #333;\n        background-color: #e6e6e6;\n        border-color: #8c8c8c\n    }\n\n    .btn-default:hover {\n        color: #333;\n        background-color: #e6e6e6;\n        border-color: #adadad\n    }\n\n    .btn-default.active, .btn-default:active, .open > .dropdown-toggle.btn-default {\n        color: #333;\n        background-color: #e6e6e6;\n        background-image: none;\n        border-color: #adadad\n    }\n\n        .btn-default.active.focus, .btn-default.active:focus, .btn-default.active:hover, .btn-default:active.focus, .btn-default:active:focus, .btn-default:active:hover, .open > .dropdown-toggle.btn-default.focus, .open > .dropdown-toggle.btn-default:focus, .open > .dropdown-toggle.btn-default:hover {\n            color: #333;\n            background-color: #d4d4d4;\n            border-color: #8c8c8c\n        }\n\n    .btn-default.disabled.focus, .btn-default.disabled:focus, .btn-default.disabled:hover, .btn-default[disabled].focus, .btn-default[disabled]:focus, .btn-default[disabled]:hover, fieldset[disabled] .btn-default.focus, fieldset[disabled] .btn-default:focus, fieldset[disabled] .btn-default:hover {\n        background-color: #fff;\n        border-color: #ccc\n    }\n\n    .btn-default .badge {\n        color: #fff;\n        background-color: #333\n    }\n\n.btn-primary {\n    color: #fff;\n    background-color: #337ab7;\n    border-color: #2e6da4\n}\n\n    .btn-primary.focus, .btn-primary:focus {\n        color: #fff;\n        background-color: #286090;\n        border-color: #122b40\n    }\n\n    .btn-primary:hover {\n        color: #fff;\n        background-color: #286090;\n        border-color: #204d74\n    }\n\n    .btn-primary.active, .btn-primary:active, .open > .dropdown-toggle.btn-primary {\n        color: #fff;\n        background-color: #286090;\n        background-image: none;\n        border-color: #204d74\n    }\n\n        .btn-primary.active.focus, .btn-primary.active:focus, .btn-primary.active:hover, .btn-primary:active.focus, .btn-primary:active:focus, .btn-primary:active:hover, .open > .dropdown-toggle.btn-primary.focus, .open > .dropdown-toggle.btn-primary:focus, .open > .dropdown-toggle.btn-primary:hover {\n            color: #fff;\n            background-color: #204d74;\n            border-color: #122b40\n        }\n\n    .btn-primary.disabled.focus, .btn-primary.disabled:focus, .btn-primary.disabled:hover, .btn-primary[disabled].focus, .btn-primary[disabled]:focus, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary.focus, fieldset[disabled] .btn-primary:focus, fieldset[disabled] .btn-primary:hover {\n        background-color: #337ab7;\n        border-color: #2e6da4\n    }\n\n    .btn-primary .badge {\n        color: #337ab7;\n        background-color: #fff\n    }\n\n.btn-success {\n    color: #fff;\n    background-color: #5cb85c;\n    border-color: #4cae4c\n}\n\n    .btn-success.focus, .btn-success:focus {\n        color: #fff;\n        background-color: #449d44;\n        border-color: #255625\n    }\n\n    .btn-success:hover {\n        color: #fff;\n        background-color: #449d44;\n        border-color: #398439\n    }\n\n    .btn-success.active, .btn-success:active, .open > .dropdown-toggle.btn-success {\n        color: #fff;\n        background-color: #449d44;\n        background-image: none;\n        border-color: #398439\n    }\n\n        .btn-success.active.focus, .btn-success.active:focus, .btn-success.active:hover, .btn-success:active.focus, .btn-success:active:focus, .btn-success:active:hover, .open > .dropdown-toggle.btn-success.focus, .open > .dropdown-toggle.btn-success:focus, .open > .dropdown-toggle.btn-success:hover {\n            color: #fff;\n            background-color: #398439;\n            border-color: #255625\n        }\n\n    .btn-success.disabled.focus, .btn-success.disabled:focus, .btn-success.disabled:hover, .btn-success[disabled].focus, .btn-success[disabled]:focus, .btn-success[disabled]:hover, fieldset[disabled] .btn-success.focus, fieldset[disabled] .btn-success:focus, fieldset[disabled] .btn-success:hover {\n        background-color: #5cb85c;\n        border-color: #4cae4c\n    }\n\n    .btn-success .badge {\n        color: #5cb85c;\n        background-color: #fff\n    }\n\n.btn-info {\n    color: #fff;\n    background-color: #5bc0de;\n    border-color: #46b8da\n}\n\n    .btn-info.focus, .btn-info:focus {\n        color: #fff;\n        background-color: #31b0d5;\n        border-color: #1b6d85\n    }\n\n    .btn-info:hover {\n        color: #fff;\n        background-color: #31b0d5;\n        border-color: #269abc\n    }\n\n    .btn-info.active, .btn-info:active, .open > .dropdown-toggle.btn-info {\n        color: #fff;\n        background-color: #31b0d5;\n        background-image: none;\n        border-color: #269abc\n    }\n\n        .btn-info.active.focus, .btn-info.active:focus, .btn-info.active:hover, .btn-info:active.focus, .btn-info:active:focus, .btn-info:active:hover, .open > .dropdown-toggle.btn-info.focus, .open > .dropdown-toggle.btn-info:focus, .open > .dropdown-toggle.btn-info:hover {\n            color: #fff;\n            background-color: #269abc;\n            border-color: #1b6d85\n        }\n\n    .btn-info.disabled.focus, .btn-info.disabled:focus, .btn-info.disabled:hover, .btn-info[disabled].focus, .btn-info[disabled]:focus, .btn-info[disabled]:hover, fieldset[disabled] .btn-info.focus, fieldset[disabled] .btn-info:focus, fieldset[disabled] .btn-info:hover {\n        background-color: #5bc0de;\n        border-color: #46b8da\n    }\n\n    .btn-info .badge {\n        color: #5bc0de;\n        background-color: #fff\n    }\n\n.btn-warning {\n    color: #fff;\n    background-color: #f0ad4e;\n    border-color: #eea236\n}\n\n    .btn-warning.focus, .btn-warning:focus {\n        color: #fff;\n        background-color: #ec971f;\n        border-color: #985f0d\n    }\n\n    .btn-warning:hover {\n        color: #fff;\n        background-color: #ec971f;\n        border-color: #d58512\n    }\n\n    .btn-warning.active, .btn-warning:active, .open > .dropdown-toggle.btn-warning {\n        color: #fff;\n        background-color: #ec971f;\n        background-image: none;\n        border-color: #d58512\n    }\n\n        .btn-warning.active.focus, .btn-warning.active:focus, .btn-warning.active:hover, .btn-warning:active.focus, .btn-warning:active:focus, .btn-warning:active:hover, .open > .dropdown-toggle.btn-warning.focus, .open > .dropdown-toggle.btn-warning:focus, .open > .dropdown-toggle.btn-warning:hover {\n            color: #fff;\n            background-color: #d58512;\n            border-color: #985f0d\n        }\n\n    .btn-warning.disabled.focus, .btn-warning.disabled:focus, .btn-warning.disabled:hover, .btn-warning[disabled].focus, .btn-warning[disabled]:focus, .btn-warning[disabled]:hover, fieldset[disabled] .btn-warning.focus, fieldset[disabled] .btn-warning:focus, fieldset[disabled] .btn-warning:hover {\n        background-color: #f0ad4e;\n        border-color: #eea236\n    }\n\n    .btn-warning .badge {\n        color: #f0ad4e;\n        background-color: #fff\n    }\n\n.btn-danger {\n    color: #fff;\n    background-color: #d9534f;\n    border-color: #d43f3a\n}\n\n    .btn-danger.focus, .btn-danger:focus {\n        color: #fff;\n        background-color: #c9302c;\n        border-color: #761c19\n    }\n\n    .btn-danger:hover {\n        color: #fff;\n        background-color: #c9302c;\n        border-color: #ac2925\n    }\n\n    .btn-danger.active, .btn-danger:active, .open > .dropdown-toggle.btn-danger {\n        color: #fff;\n        background-color: #c9302c;\n        background-image: none;\n        border-color: #ac2925\n    }\n\n        .btn-danger.active.focus, .btn-danger.active:focus, .btn-danger.active:hover, .btn-danger:active.focus, .btn-danger:active:focus, .btn-danger:active:hover, .open > .dropdown-toggle.btn-danger.focus, .open > .dropdown-toggle.btn-danger:focus, .open > .dropdown-toggle.btn-danger:hover {\n            color: #fff;\n            background-color: #ac2925;\n            border-color: #761c19\n        }\n\n    .btn-danger.disabled.focus, .btn-danger.disabled:focus, .btn-danger.disabled:hover, .btn-danger[disabled].focus, .btn-danger[disabled]:focus, .btn-danger[disabled]:hover, fieldset[disabled] .btn-danger.focus, fieldset[disabled] .btn-danger:focus, fieldset[disabled] .btn-danger:hover {\n        background-color: #d9534f;\n        border-color: #d43f3a\n    }\n\n    .btn-danger .badge {\n        color: #d9534f;\n        background-color: #fff\n    }\n\n.btn-link {\n    font-weight: 400;\n    color: #337ab7;\n    border-radius: 0\n}\n\n    .btn-link, .btn-link.active, .btn-link:active, .btn-link[disabled], fieldset[disabled] .btn-link {\n        background-color: transparent;\n        -webkit-box-shadow: none;\n        box-shadow: none\n    }\n\n        .btn-link, .btn-link:active, .btn-link:focus, .btn-link:hover {\n            border-color: transparent\n        }\n\n            .btn-link:focus, .btn-link:hover {\n                color: #23527c;\n                text-decoration: underline;\n                background-color: transparent\n            }\n\n            .btn-link[disabled]:focus, .btn-link[disabled]:hover, fieldset[disabled] .btn-link:focus, fieldset[disabled] .btn-link:hover {\n                color: #777;\n                text-decoration: none\n            }\n\n.btn-group-lg > .btn, .btn-lg {\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 6px\n}\n\n.btn-group-sm > .btn, .btn-sm {\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px\n}\n\n.btn-group-xs > .btn, .btn-xs {\n    padding: 1px 5px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px\n}\n\n.btn-block {\n    display: block;\n    width: 100%\n}\n\n    .btn-block + .btn-block {\n        margin-top: 5px\n    }\n\ninput[type=button].btn-block, input[type=reset].btn-block, input[type=submit].btn-block {\n    width: 100%\n}\n\n.fade {\n    opacity: 0;\n    -webkit-transition: opacity .15s linear;\n    -o-transition: opacity .15s linear;\n    transition: opacity .15s linear\n}\n\n    .fade.in {\n        opacity: 1\n    }\n\n.collapse {\n    display: none\n}\n\n    .collapse.in {\n        display: block\n    }\n\ntr.collapse.in {\n    display: table-row\n}\n\ntbody.collapse.in {\n    display: table-row-group\n}\n\n.collapsing {\n    position: relative;\n    height: 0;\n    overflow: hidden;\n    -webkit-transition-property: height,visibility;\n    -o-transition-property: height,visibility;\n    transition-property: height,visibility;\n    -webkit-transition-duration: .35s;\n    -o-transition-duration: .35s;\n    transition-duration: .35s;\n    -webkit-transition-timing-function: ease;\n    -o-transition-timing-function: ease;\n    transition-timing-function: ease\n}\n\n.caret {\n    display: inline-block;\n    width: 0;\n    height: 0;\n    margin-left: 2px;\n    vertical-align: middle;\n    border-top: 4px dashed;\n    border-right: 4px solid transparent;\n    border-left: 4px solid transparent\n}\n\n.dropdown, .dropup {\n    position: relative\n}\n\n.dropdown-toggle:focus {\n    outline: 0\n}\n\n.dropdown-menu {\n    position: absolute;\n    top: 100%;\n    left: 0;\n    z-index: 1000;\n    display: none;\n    float: left;\n    min-width: 160px;\n    padding: 5px 0;\n    margin: 2px 0 0;\n    font-size: 14px;\n    text-align: left;\n    list-style: none;\n    background-color: #fff;\n    background-clip: padding-box;\n    border: 1px solid rgba(0,0,0,.15);\n    border-radius: 4px;\n    -webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175);\n    box-shadow: 0 6px 12px rgba(0,0,0,.175)\n}\n\n    .dropdown-menu.pull-right {\n        right: 0;\n        left: auto\n    }\n\n    .dropdown-menu .divider {\n        height: 1px;\n        margin: 9px 0;\n        overflow: hidden;\n        background-color: #e5e5e5\n    }\n\n    .dropdown-menu > li > a {\n        display: block;\n        padding: 3px 20px;\n        clear: both;\n        font-weight: 400;\n        line-height: 1.42857143;\n        color: #333;\n        white-space: nowrap\n    }\n\n        .dropdown-menu > li > a:focus, .dropdown-menu > li > a:hover {\n            color: #262626;\n            text-decoration: none;\n            background-color: #f5f5f5\n        }\n\n    .dropdown-menu > .active > a, .dropdown-menu > .active > a:focus, .dropdown-menu > .active > a:hover {\n        color: #fff;\n        text-decoration: none;\n        background-color: #337ab7;\n        outline: 0\n    }\n\n    .dropdown-menu > .disabled > a, .dropdown-menu > .disabled > a:focus, .dropdown-menu > .disabled > a:hover {\n        color: #777\n    }\n\n        .dropdown-menu > .disabled > a:focus, .dropdown-menu > .disabled > a:hover {\n            text-decoration: none;\n            cursor: not-allowed;\n            background-color: transparent;\n            background-image: none\n        }\n\n.open > .dropdown-menu {\n    display: block\n}\n\n.open > a {\n    outline: 0\n}\n\n.dropdown-menu-right {\n    right: 0;\n    left: auto\n}\n\n.dropdown-menu-left {\n    right: auto;\n    left: 0\n}\n\n.dropdown-header {\n    display: block;\n    padding: 3px 20px;\n    font-size: 12px;\n    line-height: 1.42857143;\n    color: #777;\n    white-space: nowrap\n}\n\n.dropdown-backdrop {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 990\n}\n\n.pull-right > .dropdown-menu {\n    right: 0;\n    left: auto\n}\n\n.dropup .caret, .navbar-fixed-bottom .dropdown .caret {\n    content: \"\";\n    border-top: 0;\n    border-bottom: 4px dashed\n}\n\n.dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu {\n    top: auto;\n    bottom: 100%;\n    margin-bottom: 2px\n}\n\n.btn-group, .btn-group-vertical {\n    position: relative;\n    display: inline-block;\n    vertical-align: middle\n}\n\n    .btn-group-vertical > .btn, .btn-group > .btn {\n        position: relative;\n        float: left\n    }\n\n        .btn-group-vertical > .btn.active, .btn-group-vertical > .btn:active, .btn-group-vertical > .btn:focus, .btn-group-vertical > .btn:hover, .btn-group > .btn.active, .btn-group > .btn:active, .btn-group > .btn:focus, .btn-group > .btn:hover {\n            z-index: 2\n        }\n\n    .btn-group .btn + .btn, .btn-group .btn + .btn-group, .btn-group .btn-group + .btn, .btn-group .btn-group + .btn-group {\n        margin-left: -1px\n    }\n\n.btn-toolbar {\n    margin-left: -5px\n}\n\n    .btn-toolbar .btn, .btn-toolbar .btn-group, .btn-toolbar .input-group {\n        float: left\n    }\n\n    .btn-toolbar > .btn, .btn-toolbar > .btn-group, .btn-toolbar > .input-group {\n        margin-left: 5px\n    }\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n    border-radius: 0\n}\n\n.btn-group > .btn:first-child {\n    margin-left: 0\n}\n\n    .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n        border-top-right-radius: 0;\n        border-bottom-right-radius: 0\n    }\n\n.btn-group > .btn:last-child:not(:first-child), .btn-group > .dropdown-toggle:not(:first-child) {\n    border-top-left-radius: 0;\n    border-bottom-left-radius: 0\n}\n\n.btn-group > .btn-group {\n    float: left\n}\n\n    .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n        border-radius: 0\n    }\n\n    .btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, .btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n        border-top-right-radius: 0;\n        border-bottom-right-radius: 0\n    }\n\n    .btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n        border-top-left-radius: 0;\n        border-bottom-left-radius: 0\n    }\n\n.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle {\n    outline: 0\n}\n\n.btn-group > .btn + .dropdown-toggle {\n    padding-right: 8px;\n    padding-left: 8px\n}\n\n.btn-group > .btn-lg + .dropdown-toggle {\n    padding-right: 12px;\n    padding-left: 12px\n}\n\n.btn-group.open .dropdown-toggle {\n    -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,.125);\n    box-shadow: inset 0 3px 5px rgba(0,0,0,.125)\n}\n\n    .btn-group.open .dropdown-toggle.btn-link {\n        -webkit-box-shadow: none;\n        box-shadow: none\n    }\n\n.btn .caret {\n    margin-left: 0\n}\n\n.btn-lg .caret {\n    border-width: 5px 5px 0\n}\n\n.dropup .btn-lg .caret {\n    border-width: 0 5px 5px\n}\n\n.btn-group-vertical > .btn, .btn-group-vertical > .btn-group, .btn-group-vertical > .btn-group > .btn {\n    display: block;\n    float: none;\n    width: 100%;\n    max-width: 100%\n}\n\n    .btn-group-vertical > .btn-group > .btn {\n        float: none\n    }\n\n    .btn-group-vertical > .btn + .btn, .btn-group-vertical > .btn + .btn-group, .btn-group-vertical > .btn-group + .btn, .btn-group-vertical > .btn-group + .btn-group {\n        margin-top: -1px;\n        margin-left: 0\n    }\n\n    .btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n        border-radius: 0\n    }\n\n    .btn-group-vertical > .btn:first-child:not(:last-child) {\n        border-radius: 4px 4px 0 0\n    }\n\n    .btn-group-vertical > .btn:last-child:not(:first-child) {\n        border-radius: 0 0 4px 4px\n    }\n\n    .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n        border-radius: 0\n    }\n\n    .btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, .btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n        border-bottom-right-radius: 0;\n        border-bottom-left-radius: 0\n    }\n\n    .btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n        border-top-left-radius: 0;\n        border-top-right-radius: 0\n    }\n\n.btn-group-justified {\n    display: table;\n    width: 100%;\n    table-layout: fixed;\n    border-collapse: separate\n}\n\n    .btn-group-justified > .btn, .btn-group-justified > .btn-group {\n        display: table-cell;\n        float: none;\n        width: 1%\n    }\n\n        .btn-group-justified > .btn-group .btn {\n            width: 100%\n        }\n\n        .btn-group-justified > .btn-group .dropdown-menu {\n            left: auto\n        }\n\n[data-toggle=buttons] > .btn input[type=checkbox], [data-toggle=buttons] > .btn input[type=radio], [data-toggle=buttons] > .btn-group > .btn input[type=checkbox], [data-toggle=buttons] > .btn-group > .btn input[type=radio] {\n    position: absolute;\n    clip: rect(0,0,0,0);\n    pointer-events: none\n}\n\n.input-group {\n    position: relative;\n    display: table;\n    border-collapse: separate\n}\n\n    .input-group[class*=col-] {\n        float: none;\n        padding-right: 0;\n        padding-left: 0\n    }\n\n    .input-group .form-control {\n        position: relative;\n        z-index: 2;\n        float: left;\n        width: 100%;\n        margin-bottom: 0\n    }\n\n        .input-group .form-control:focus {\n            z-index: 3\n        }\n\n.input-group-lg > .form-control, .input-group-lg > .input-group-addon, .input-group-lg > .input-group-btn > .btn {\n    height: 46px;\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 6px\n}\n\nselect.input-group-lg > .form-control, select.input-group-lg > .input-group-addon, select.input-group-lg > .input-group-btn > .btn {\n    height: 46px;\n    line-height: 46px\n}\n\nselect[multiple].input-group-lg > .form-control, select[multiple].input-group-lg > .input-group-addon, select[multiple].input-group-lg > .input-group-btn > .btn, textarea.input-group-lg > .form-control, textarea.input-group-lg > .input-group-addon, textarea.input-group-lg > .input-group-btn > .btn {\n    height: auto\n}\n\n.input-group-sm > .form-control, .input-group-sm > .input-group-addon, .input-group-sm > .input-group-btn > .btn {\n    height: 30px;\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px\n}\n\nselect.input-group-sm > .form-control, select.input-group-sm > .input-group-addon, select.input-group-sm > .input-group-btn > .btn {\n    height: 30px;\n    line-height: 30px\n}\n\nselect[multiple].input-group-sm > .form-control, select[multiple].input-group-sm > .input-group-addon, select[multiple].input-group-sm > .input-group-btn > .btn, textarea.input-group-sm > .form-control, textarea.input-group-sm > .input-group-addon, textarea.input-group-sm > .input-group-btn > .btn {\n    height: auto\n}\n\n.input-group .form-control, .input-group-addon, .input-group-btn {\n    display: table-cell\n}\n\n    .input-group .form-control:not(:first-child):not(:last-child), .input-group-addon:not(:first-child):not(:last-child), .input-group-btn:not(:first-child):not(:last-child) {\n        border-radius: 0\n    }\n\n.input-group-addon, .input-group-btn {\n    width: 1%;\n    white-space: nowrap;\n    vertical-align: middle\n}\n\n.input-group-addon {\n    padding: 6px 12px;\n    font-size: 14px;\n    font-weight: 400;\n    line-height: 1;\n    color: #555;\n    text-align: center;\n    background-color: #eee;\n    border: 1px solid #ccc;\n    border-radius: 4px\n}\n\n    .input-group-addon.input-sm {\n        padding: 5px 10px;\n        font-size: 12px;\n        border-radius: 3px\n    }\n\n    .input-group-addon.input-lg {\n        padding: 10px 16px;\n        font-size: 18px;\n        border-radius: 6px\n    }\n\n    .input-group-addon input[type=checkbox], .input-group-addon input[type=radio] {\n        margin-top: 0\n    }\n\n    .input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child > .btn, .input-group-btn:first-child > .btn-group > .btn, .input-group-btn:first-child > .dropdown-toggle, .input-group-btn:last-child > .btn-group:not(:last-child) > .btn, .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) {\n        border-top-right-radius: 0;\n        border-bottom-right-radius: 0\n    }\n\n    .input-group-addon:first-child {\n        border-right: 0\n    }\n\n    .input-group .form-control:last-child, .input-group-addon:last-child, .input-group-btn:first-child > .btn-group:not(:first-child) > .btn, .input-group-btn:first-child > .btn:not(:first-child), .input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group > .btn, .input-group-btn:last-child > .dropdown-toggle {\n        border-top-left-radius: 0;\n        border-bottom-left-radius: 0\n    }\n\n    .input-group-addon:last-child {\n        border-left: 0\n    }\n\n.input-group-btn {\n    position: relative;\n    font-size: 0;\n    white-space: nowrap\n}\n\n    .input-group-btn > .btn {\n        position: relative\n    }\n\n        .input-group-btn > .btn + .btn {\n            margin-left: -1px\n        }\n\n        .input-group-btn > .btn:active, .input-group-btn > .btn:focus, .input-group-btn > .btn:hover {\n            z-index: 2\n        }\n\n    .input-group-btn:first-child > .btn, .input-group-btn:first-child > .btn-group {\n        margin-right: -1px\n    }\n\n    .input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group {\n        z-index: 2;\n        margin-left: -1px\n    }\n\n.nav {\n    padding-left: 0;\n    margin-bottom: 0;\n    list-style: none\n}\n\n    .nav > li {\n        position: relative;\n        display: block\n    }\n\n        .nav > li > a {\n            position: relative;\n            display: block;\n            padding: 10px 15px\n        }\n\n            .nav > li > a:focus, .nav > li > a:hover {\n                text-decoration: none;\n                background-color: #eee\n            }\n\n        .nav > li.disabled > a {\n            color: #777\n        }\n\n            .nav > li.disabled > a:focus, .nav > li.disabled > a:hover {\n                color: #777;\n                text-decoration: none;\n                cursor: not-allowed;\n                background-color: transparent\n            }\n\n    .nav .open > a, .nav .open > a:focus, .nav .open > a:hover {\n        background-color: #eee;\n        border-color: #337ab7\n    }\n\n    .nav .nav-divider {\n        height: 1px;\n        margin: 9px 0;\n        overflow: hidden;\n        background-color: #e5e5e5\n    }\n\n    .nav > li > a > img {\n        max-width: none\n    }\n\n.nav-tabs {\n    border-bottom: 1px solid #ddd\n}\n\n    .nav-tabs > li {\n        float: left;\n        margin-bottom: -1px\n    }\n\n        .nav-tabs > li > a {\n            margin-right: 2px;\n            line-height: 1.42857143;\n            border: 1px solid transparent;\n            border-radius: 4px 4px 0 0\n        }\n\n            .nav-tabs > li > a:hover {\n                border-color: #eee #eee #ddd\n            }\n\n        .nav-tabs > li.active > a, .nav-tabs > li.active > a:focus, .nav-tabs > li.active > a:hover {\n            color: #555;\n            cursor: default;\n            background-color: #fff;\n            border: 1px solid #ddd;\n            border-bottom-color: transparent\n        }\n\n    .nav-tabs.nav-justified {\n        width: 100%;\n        border-bottom: 0\n    }\n\n        .nav-tabs.nav-justified > li {\n            float: none\n        }\n\n            .nav-tabs.nav-justified > li > a {\n                margin-bottom: 5px;\n                text-align: center;\n                margin-right: 0;\n                border-radius: 4px\n            }\n\n        .nav-tabs.nav-justified > .dropdown .dropdown-menu {\n            top: auto;\n            left: auto\n        }\n\n        .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:focus, .nav-tabs.nav-justified > .active > a:hover {\n            border: 1px solid #ddd\n        }\n\n.nav-pills > li {\n    float: left\n}\n\n    .nav-pills > li > a {\n        border-radius: 4px\n    }\n\n    .nav-pills > li + li {\n        margin-left: 2px\n    }\n\n    .nav-pills > li.active > a, .nav-pills > li.active > a:focus, .nav-pills > li.active > a:hover {\n        color: #fff;\n        background-color: #337ab7\n    }\n\n.nav-stacked > li {\n    float: none\n}\n\n    .nav-stacked > li + li {\n        margin-top: 2px;\n        margin-left: 0\n    }\n\n.nav-justified {\n    width: 100%\n}\n\n    .nav-justified > li {\n        float: none\n    }\n\n        .nav-justified > li > a {\n            margin-bottom: 5px;\n            text-align: center\n        }\n\n    .nav-justified > .dropdown .dropdown-menu {\n        top: auto;\n        left: auto\n    }\n\n@media (min-width:768px) {\n    .navbar-right .dropdown-menu {\n        right: 0;\n        left: auto\n    }\n\n    .navbar-right .dropdown-menu-left {\n        right: auto;\n        left: 0\n    }\n\n    .nav-tabs.nav-justified > li {\n        display: table-cell;\n        width: 1%\n    }\n\n        .nav-tabs.nav-justified > li > a {\n            margin-bottom: 0;\n            border-bottom: 1px solid #ddd;\n            border-radius: 4px 4px 0 0\n        }\n\n    .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:focus, .nav-tabs.nav-justified > .active > a:hover {\n        border-bottom-color: #fff\n    }\n\n    .nav-justified > li {\n        display: table-cell;\n        width: 1%\n    }\n\n        .nav-justified > li > a {\n            margin-bottom: 0\n        }\n}\n\n.nav-tabs-justified {\n    border-bottom: 0\n}\n\n    .nav-tabs-justified > li > a {\n        margin-right: 0;\n        border-radius: 4px\n    }\n\n    .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:focus, .nav-tabs-justified > .active > a:hover {\n        border: 1px solid #ddd\n    }\n\n@media (min-width:768px) {\n    .nav-tabs-justified > li > a {\n        border-bottom: 1px solid #ddd;\n        border-radius: 4px 4px 0 0\n    }\n\n    .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:focus, .nav-tabs-justified > .active > a:hover {\n        border-bottom-color: #fff\n    }\n}\n\n.tab-content > .tab-pane {\n    display: none\n}\n\n.tab-content > .active {\n    display: block\n}\n\n.nav-tabs .dropdown-menu {\n    margin-top: -1px;\n    border-top-left-radius: 0;\n    border-top-right-radius: 0\n}\n\n.navbar {\n    position: relative;\n    min-height: 50px;\n    margin-bottom: 20px;\n    border: 1px solid transparent\n}\n\n.navbar-collapse {\n    padding-right: 15px;\n    padding-left: 15px;\n    overflow-x: visible;\n    border-top: 1px solid transparent;\n    -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n    box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n    -webkit-overflow-scrolling: touch\n}\n\n    .navbar-collapse.in {\n        overflow-y: auto\n    }\n\n.navbar-fixed-bottom, .navbar-fixed-top {\n    position: fixed;\n    right: 0;\n    left: 0;\n    z-index: 1030\n}\n\n    .navbar-fixed-bottom .navbar-collapse, .navbar-fixed-top .navbar-collapse {\n        max-height: 340px\n    }\n\n@media (max-device-width:480px) and (orientation:landscape) {\n    .navbar-fixed-bottom .navbar-collapse, .navbar-fixed-top .navbar-collapse {\n        max-height: 200px\n    }\n}\n\n@media (min-width:768px) {\n    .navbar {\n        border-radius: 4px\n    }\n\n    .navbar-header {\n        float: left\n    }\n\n    .navbar-collapse {\n        width: auto;\n        border-top: 0;\n        -webkit-box-shadow: none;\n        box-shadow: none\n    }\n\n        .navbar-collapse.collapse {\n            display: block !important;\n            height: auto !important;\n            padding-bottom: 0;\n            overflow: visible !important\n        }\n\n        .navbar-collapse.in {\n            overflow-y: visible\n        }\n\n    .navbar-fixed-bottom .navbar-collapse, .navbar-fixed-top .navbar-collapse, .navbar-static-top .navbar-collapse {\n        padding-right: 0;\n        padding-left: 0\n    }\n\n    .navbar-fixed-bottom, .navbar-fixed-top {\n        border-radius: 0\n    }\n}\n\n.navbar-fixed-top {\n    top: 0;\n    border-width: 0 0 1px\n}\n\n.navbar-fixed-bottom {\n    bottom: 0;\n    margin-bottom: 0;\n    border-width: 1px 0 0\n}\n\n.container-fluid > .navbar-collapse, .container-fluid > .navbar-header, .container > .navbar-collapse, .container > .navbar-header {\n    margin-right: -15px;\n    margin-left: -15px\n}\n\n.navbar-static-top {\n    z-index: 1000;\n    border-width: 0 0 1px\n}\n\n.navbar-brand {\n    float: left;\n    height: 50px;\n    padding: 15px;\n    font-size: 18px;\n    line-height: 20px\n}\n\n    .navbar-brand:focus, .navbar-brand:hover {\n        text-decoration: none\n    }\n\n    .navbar-brand > img {\n        display: block\n    }\n\n@media (min-width:768px) {\n    .container-fluid > .navbar-collapse, .container-fluid > .navbar-header, .container > .navbar-collapse, .container > .navbar-header {\n        margin-right: 0;\n        margin-left: 0\n    }\n\n    .navbar-static-top {\n        border-radius: 0\n    }\n\n    .navbar > .container .navbar-brand, .navbar > .container-fluid .navbar-brand {\n        margin-left: -15px\n    }\n\n    .navbar-toggle {\n        display: none\n    }\n}\n\n.navbar-toggle {\n    position: relative;\n    float: right;\n    padding: 9px 10px;\n    margin-right: 15px;\n    margin-top: 8px;\n    margin-bottom: 8px;\n    background-color: transparent;\n    background-image: none;\n    border: 1px solid transparent;\n    border-radius: 4px\n}\n\n    .navbar-toggle:focus {\n        outline: 0\n    }\n\n    .navbar-toggle .icon-bar {\n        display: block;\n        width: 22px;\n        height: 2px;\n        border-radius: 1px\n    }\n\n        .navbar-toggle .icon-bar + .icon-bar {\n            margin-top: 4px\n        }\n\n.navbar-nav {\n    margin: 7.5px -15px\n}\n\n    .navbar-nav > li > a {\n        padding-top: 10px;\n        padding-bottom: 10px;\n        line-height: 20px\n    }\n\n@media (max-width:767px) {\n    .navbar-nav .open .dropdown-menu {\n        position: static;\n        float: none;\n        width: auto;\n        margin-top: 0;\n        background-color: transparent;\n        border: 0;\n        -webkit-box-shadow: none;\n        box-shadow: none\n    }\n\n        .navbar-nav .open .dropdown-menu .dropdown-header, .navbar-nav .open .dropdown-menu > li > a {\n            padding: 5px 15px 5px 25px\n        }\n\n        .navbar-nav .open .dropdown-menu > li > a {\n            line-height: 20px\n        }\n\n            .navbar-nav .open .dropdown-menu > li > a:focus, .navbar-nav .open .dropdown-menu > li > a:hover {\n                background-image: none\n            }\n}\n\n@media (min-width:768px) {\n    .navbar-nav {\n        float: left;\n        margin: 0\n    }\n\n        .navbar-nav > li {\n            float: left\n        }\n\n            .navbar-nav > li > a {\n                padding-top: 15px;\n                padding-bottom: 15px\n            }\n\n    .navbar-form .form-group {\n        display: inline-block;\n        margin-bottom: 0;\n        vertical-align: middle\n    }\n\n    .navbar-form .form-control {\n        display: inline-block;\n        width: auto;\n        vertical-align: middle\n    }\n\n    .navbar-form .form-control-static {\n        display: inline-block\n    }\n\n    .navbar-form .input-group {\n        display: inline-table;\n        vertical-align: middle\n    }\n\n        .navbar-form .input-group .form-control, .navbar-form .input-group .input-group-addon, .navbar-form .input-group .input-group-btn {\n            width: auto\n        }\n\n        .navbar-form .input-group > .form-control {\n            width: 100%\n        }\n\n    .navbar-form .control-label {\n        margin-bottom: 0;\n        vertical-align: middle\n    }\n\n    .navbar-form .checkbox, .navbar-form .radio {\n        display: inline-block;\n        margin-top: 0;\n        margin-bottom: 0;\n        vertical-align: middle\n    }\n\n        .navbar-form .checkbox label, .navbar-form .radio label {\n            padding-left: 0\n        }\n\n        .navbar-form .checkbox input[type=checkbox], .navbar-form .radio input[type=radio] {\n            position: relative;\n            margin-left: 0\n        }\n\n    .navbar-form .has-feedback .form-control-feedback {\n        top: 0\n    }\n}\n\n.navbar-form {\n    padding: 10px 15px;\n    border-top: 1px solid transparent;\n    border-bottom: 1px solid transparent;\n    -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);\n    box-shadow: inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);\n    margin: 8px -15px\n}\n\n@media (max-width:767px) {\n    .navbar-form .form-group {\n        margin-bottom: 5px\n    }\n\n        .navbar-form .form-group:last-child {\n            margin-bottom: 0\n        }\n\n    .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n        color: #777\n    }\n\n        .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus, .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover {\n            color: #333;\n            background-color: transparent\n        }\n\n    .navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover {\n        color: #555;\n        background-color: #e7e7e7\n    }\n\n    .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover {\n        color: #ccc;\n        background-color: transparent\n    }\n}\n\n@media (min-width:768px) {\n    .navbar-form {\n        width: auto;\n        padding-top: 0;\n        padding-bottom: 0;\n        margin-right: 0;\n        margin-left: 0;\n        border: 0;\n        -webkit-box-shadow: none;\n        box-shadow: none\n    }\n\n    .navbar-text {\n        float: left;\n        margin-right: 15px;\n        margin-left: 15px\n    }\n}\n\n.navbar-nav > li > .dropdown-menu {\n    margin-top: 0;\n    border-top-left-radius: 0;\n    border-top-right-radius: 0\n}\n\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n    margin-bottom: 0;\n    border-radius: 4px 4px 0 0\n}\n\n.navbar-btn {\n    margin-top: 8px;\n    margin-bottom: 8px\n}\n\n    .navbar-btn.btn-sm {\n        margin-top: 10px;\n        margin-bottom: 10px\n    }\n\n    .navbar-btn.btn-xs {\n        margin-top: 14px;\n        margin-bottom: 14px\n    }\n\n.navbar-text {\n    margin-top: 15px;\n    margin-bottom: 15px\n}\n\n@media (min-width:768px) {\n    .navbar-left {\n        float: left !important\n    }\n\n    .navbar-right {\n        float: right !important;\n        margin-right: -15px\n    }\n\n        .navbar-right ~ .navbar-right {\n            margin-right: 0\n        }\n}\n\n.navbar-default {\n    background-color: #f8f8f8;\n    border-color: #e7e7e7\n}\n\n    .navbar-default .navbar-brand {\n        color: #777\n    }\n\n        .navbar-default .navbar-brand:focus, .navbar-default .navbar-brand:hover {\n            color: #5e5e5e;\n            background-color: transparent\n        }\n\n    .navbar-default .navbar-nav > li > a, .navbar-default .navbar-text {\n        color: #777\n    }\n\n        .navbar-default .navbar-nav > li > a:focus, .navbar-default .navbar-nav > li > a:hover {\n            color: #333;\n            background-color: transparent\n        }\n\n    .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:focus, .navbar-default .navbar-nav > .active > a:hover {\n        color: #555;\n        background-color: #e7e7e7\n    }\n\n    .navbar-default .navbar-nav > .disabled > a, .navbar-default .navbar-nav > .disabled > a:focus, .navbar-default .navbar-nav > .disabled > a:hover {\n        color: #ccc;\n        background-color: transparent\n    }\n\n    .navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:focus, .navbar-default .navbar-nav > .open > a:hover {\n        color: #555;\n        background-color: #e7e7e7\n    }\n\n    .navbar-default .navbar-toggle {\n        border-color: #ddd\n    }\n\n        .navbar-default .navbar-toggle:focus, .navbar-default .navbar-toggle:hover {\n            background-color: #ddd\n        }\n\n        .navbar-default .navbar-toggle .icon-bar {\n            background-color: #888\n        }\n\n    .navbar-default .navbar-collapse, .navbar-default .navbar-form {\n        border-color: #e7e7e7\n    }\n\n    .navbar-default .navbar-link {\n        color: #777\n    }\n\n        .navbar-default .navbar-link:hover {\n            color: #333\n        }\n\n    .navbar-default .btn-link {\n        color: #777\n    }\n\n        .navbar-default .btn-link:focus, .navbar-default .btn-link:hover {\n            color: #333\n        }\n\n        .navbar-default .btn-link[disabled]:focus, .navbar-default .btn-link[disabled]:hover, fieldset[disabled] .navbar-default .btn-link:focus, fieldset[disabled] .navbar-default .btn-link:hover {\n            color: #ccc\n        }\n\n.navbar-inverse {\n    background-color: #222;\n    border-color: #080808\n}\n\n    .navbar-inverse .navbar-brand {\n        color: #9d9d9d\n    }\n\n        .navbar-inverse .navbar-brand:focus, .navbar-inverse .navbar-brand:hover {\n            color: #fff;\n            background-color: transparent\n        }\n\n    .navbar-inverse .navbar-nav > li > a, .navbar-inverse .navbar-text {\n        color: #9d9d9d\n    }\n\n        .navbar-inverse .navbar-nav > li > a:focus, .navbar-inverse .navbar-nav > li > a:hover {\n            color: #fff;\n            background-color: transparent\n        }\n\n    .navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:focus, .navbar-inverse .navbar-nav > .active > a:hover {\n        color: #fff;\n        background-color: #080808\n    }\n\n    .navbar-inverse .navbar-nav > .disabled > a, .navbar-inverse .navbar-nav > .disabled > a:focus, .navbar-inverse .navbar-nav > .disabled > a:hover {\n        color: #444;\n        background-color: transparent\n    }\n\n    .navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:focus, .navbar-inverse .navbar-nav > .open > a:hover {\n        color: #fff;\n        background-color: #080808\n    }\n\n@media (max-width:767px) {\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n        border-color: #080808\n    }\n\n    .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n        background-color: #080808\n    }\n\n    .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n        color: #9d9d9d\n    }\n\n        .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus, .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover {\n            color: #fff;\n            background-color: transparent\n        }\n\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover {\n        color: #fff;\n        background-color: #080808\n    }\n\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover {\n        color: #444;\n        background-color: transparent\n    }\n}\n\n.navbar-inverse .navbar-toggle {\n    border-color: #333\n}\n\n    .navbar-inverse .navbar-toggle:focus, .navbar-inverse .navbar-toggle:hover {\n        background-color: #333\n    }\n\n    .navbar-inverse .navbar-toggle .icon-bar {\n        background-color: #fff\n    }\n\n.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {\n    border-color: #101010\n}\n\n.navbar-inverse .navbar-link {\n    color: #9d9d9d\n}\n\n    .navbar-inverse .navbar-link:hover {\n        color: #fff\n    }\n\n.navbar-inverse .btn-link {\n    color: #9d9d9d\n}\n\n    .navbar-inverse .btn-link:focus, .navbar-inverse .btn-link:hover {\n        color: #fff\n    }\n\n    .navbar-inverse .btn-link[disabled]:focus, .navbar-inverse .btn-link[disabled]:hover, fieldset[disabled] .navbar-inverse .btn-link:focus, fieldset[disabled] .navbar-inverse .btn-link:hover {\n        color: #444\n    }\n\n.breadcrumb {\n    padding: 8px 15px;\n    margin-bottom: 20px;\n    list-style: none;\n    background-color: #f5f5f5;\n    border-radius: 4px\n}\n\n    .breadcrumb > li {\n        display: inline-block\n    }\n\n        .breadcrumb > li + li:before {\n            padding: 0 5px;\n            color: #ccc;\n            content: \"/\\00a0\"\n        }\n\n    .breadcrumb > .active {\n        color: #777\n    }\n\n.pagination {\n    display: inline-block;\n    padding-left: 0;\n    margin: 20px 0;\n    border-radius: 4px\n}\n\n    .pagination > li {\n        display: inline\n    }\n\n        .pagination > li > a, .pagination > li > span {\n            position: relative;\n            float: left;\n            padding: 6px 12px;\n            margin-left: -1px;\n            line-height: 1.42857143;\n            color: #337ab7;\n            text-decoration: none;\n            background-color: #fff;\n            border: 1px solid #ddd\n        }\n\n            .pagination > li > a:focus, .pagination > li > a:hover, .pagination > li > span:focus, .pagination > li > span:hover {\n                z-index: 2;\n                color: #23527c;\n                background-color: #eee;\n                border-color: #ddd\n            }\n\n        .pagination > li:first-child > a, .pagination > li:first-child > span {\n            margin-left: 0;\n            border-top-left-radius: 4px;\n            border-bottom-left-radius: 4px\n        }\n\n        .pagination > li:last-child > a, .pagination > li:last-child > span {\n            border-top-right-radius: 4px;\n            border-bottom-right-radius: 4px\n        }\n\n    .pagination > .active > a, .pagination > .active > a:focus, .pagination > .active > a:hover, .pagination > .active > span, .pagination > .active > span:focus, .pagination > .active > span:hover {\n        z-index: 3;\n        color: #fff;\n        cursor: default;\n        background-color: #337ab7;\n        border-color: #337ab7\n    }\n\n    .pagination > .disabled > a, .pagination > .disabled > a:focus, .pagination > .disabled > a:hover, .pagination > .disabled > span, .pagination > .disabled > span:focus, .pagination > .disabled > span:hover {\n        color: #777;\n        cursor: not-allowed;\n        background-color: #fff;\n        border-color: #ddd\n    }\n\n.pagination-lg > li > a, .pagination-lg > li > span {\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333\n}\n\n.pagination-lg > li:first-child > a, .pagination-lg > li:first-child > span {\n    border-top-left-radius: 6px;\n    border-bottom-left-radius: 6px\n}\n\n.pagination-lg > li:last-child > a, .pagination-lg > li:last-child > span {\n    border-top-right-radius: 6px;\n    border-bottom-right-radius: 6px\n}\n\n.pagination-sm > li > a, .pagination-sm > li > span {\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5\n}\n\n.pagination-sm > li:first-child > a, .pagination-sm > li:first-child > span {\n    border-top-left-radius: 3px;\n    border-bottom-left-radius: 3px\n}\n\n.pagination-sm > li:last-child > a, .pagination-sm > li:last-child > span {\n    border-top-right-radius: 3px;\n    border-bottom-right-radius: 3px\n}\n\n.pager {\n    padding-left: 0;\n    margin: 20px 0;\n    text-align: center;\n    list-style: none\n}\n\n    .pager li {\n        display: inline\n    }\n\n        .pager li > a, .pager li > span {\n            display: inline-block;\n            padding: 5px 14px;\n            background-color: #fff;\n            border: 1px solid #ddd;\n            border-radius: 15px\n        }\n\n            .pager li > a:focus, .pager li > a:hover {\n                text-decoration: none;\n                background-color: #eee\n            }\n\n    .pager .next > a, .pager .next > span {\n        float: right\n    }\n\n    .pager .previous > a, .pager .previous > span {\n        float: left\n    }\n\n    .pager .disabled > a, .pager .disabled > a:focus, .pager .disabled > a:hover, .pager .disabled > span {\n        color: #777;\n        cursor: not-allowed;\n        background-color: #fff\n    }\n\n.label {\n    display: inline;\n    padding: .2em .6em .3em;\n    font-size: 75%;\n    font-weight: 700;\n    line-height: 1;\n    color: #fff;\n    text-align: center;\n    white-space: nowrap;\n    vertical-align: baseline;\n    border-radius: .25em\n}\n\na.label:focus, a.label:hover {\n    color: #fff;\n    text-decoration: none;\n    cursor: pointer\n}\n\n.label:empty {\n    display: none\n}\n\n.btn .label {\n    position: relative;\n    top: -1px\n}\n\n.label-default {\n    background-color: #777\n}\n\n    .label-default[href]:focus, .label-default[href]:hover {\n        background-color: #5e5e5e\n    }\n\n.label-primary {\n    background-color: #337ab7\n}\n\n    .label-primary[href]:focus, .label-primary[href]:hover {\n        background-color: #286090\n    }\n\n.label-success {\n    background-color: #5cb85c\n}\n\n    .label-success[href]:focus, .label-success[href]:hover {\n        background-color: #449d44\n    }\n\n.label-info {\n    background-color: #5bc0de\n}\n\n    .label-info[href]:focus, .label-info[href]:hover {\n        background-color: #31b0d5\n    }\n\n.label-warning {\n    background-color: #f0ad4e\n}\n\n    .label-warning[href]:focus, .label-warning[href]:hover {\n        background-color: #ec971f\n    }\n\n.label-danger {\n    background-color: #d9534f\n}\n\n    .label-danger[href]:focus, .label-danger[href]:hover {\n        background-color: #c9302c\n    }\n\n.badge {\n    display: inline-block;\n    min-width: 10px;\n    padding: 3px 7px;\n    font-size: 12px;\n    font-weight: 700;\n    line-height: 1;\n    color: #fff;\n    text-align: center;\n    white-space: nowrap;\n    vertical-align: middle;\n    background-color: #777;\n    border-radius: 10px\n}\n\n    .badge:empty {\n        display: none\n    }\n\n.btn .badge {\n    position: relative;\n    top: -1px\n}\n\n.btn-group-xs > .btn .badge, .btn-xs .badge {\n    top: 0;\n    padding: 1px 5px\n}\n\na.badge:focus, a.badge:hover {\n    color: #fff;\n    text-decoration: none;\n    cursor: pointer\n}\n\n.list-group-item.active > .badge, .nav-pills > .active > a > .badge {\n    color: #337ab7;\n    background-color: #fff\n}\n\n.list-group-item > .badge {\n    float: right\n}\n\n    .list-group-item > .badge + .badge {\n        margin-right: 5px\n    }\n\n.nav-pills > li > a > .badge {\n    margin-left: 3px\n}\n\n.jumbotron {\n    padding-top: 30px;\n    padding-bottom: 30px;\n    margin-bottom: 30px;\n    color: inherit;\n    background-color: #eee\n}\n\n    .jumbotron .h1, .jumbotron h1 {\n        color: inherit\n    }\n\n    .jumbotron p {\n        margin-bottom: 15px;\n        font-size: 21px;\n        font-weight: 200\n    }\n\n    .jumbotron > hr {\n        border-top-color: #d5d5d5\n    }\n\n.container .jumbotron, .container-fluid .jumbotron {\n    padding-right: 15px;\n    padding-left: 15px;\n    border-radius: 6px\n}\n\n.jumbotron .container {\n    max-width: 100%\n}\n\n@media screen and (min-width:768px) {\n    .jumbotron {\n        padding-top: 48px;\n        padding-bottom: 48px\n    }\n\n    .container .jumbotron, .container-fluid .jumbotron {\n        padding-right: 60px;\n        padding-left: 60px\n    }\n\n    .jumbotron .h1, .jumbotron h1 {\n        font-size: 63px\n    }\n}\n\n.thumbnail {\n    display: block;\n    padding: 4px;\n    margin-bottom: 20px;\n    line-height: 1.42857143;\n    background-color: #fff;\n    border: 1px solid #ddd;\n    border-radius: 4px;\n    -webkit-transition: border .2s ease-in-out;\n    -o-transition: border .2s ease-in-out;\n    transition: border .2s ease-in-out\n}\n\n    .thumbnail a > img, .thumbnail > img {\n        margin-right: auto;\n        margin-left: auto\n    }\n\na.thumbnail.active, a.thumbnail:focus, a.thumbnail:hover {\n    border-color: #337ab7\n}\n\n.thumbnail .caption {\n    padding: 9px;\n    color: #333\n}\n\n.alert {\n    padding: 15px;\n    margin-bottom: 20px;\n    border: 1px solid transparent;\n    border-radius: 4px\n}\n\n    .alert h4 {\n        margin-top: 0;\n        color: inherit\n    }\n\n    .alert .alert-link {\n        font-weight: 700\n    }\n\n    .alert > p, .alert > ul {\n        margin-bottom: 0\n    }\n\n        .alert > p + p {\n            margin-top: 5px\n        }\n\n.alert-dismissable, .alert-dismissible {\n    padding-right: 35px\n}\n\n    .alert-dismissable .close, .alert-dismissible .close {\n        position: relative;\n        top: -2px;\n        right: -21px;\n        color: inherit\n    }\n\n.alert-success {\n    color: #3c763d;\n    background-color: #dff0d8;\n    border-color: #d6e9c6\n}\n\n    .alert-success hr {\n        border-top-color: #c9e2b3\n    }\n\n    .alert-success .alert-link {\n        color: #2b542c\n    }\n\n.alert-info {\n    color: #31708f;\n    background-color: #d9edf7;\n    border-color: #bce8f1\n}\n\n    .alert-info hr {\n        border-top-color: #a6e1ec\n    }\n\n    .alert-info .alert-link {\n        color: #245269\n    }\n\n.alert-warning {\n    color: #8a6d3b;\n    background-color: #fcf8e3;\n    border-color: #faebcc\n}\n\n    .alert-warning hr {\n        border-top-color: #f7e1b5\n    }\n\n    .alert-warning .alert-link {\n        color: #66512c\n    }\n\n.alert-danger {\n    color: #a94442;\n    background-color: #f2dede;\n    border-color: #ebccd1\n}\n\n    .alert-danger hr {\n        border-top-color: #e4b9c0\n    }\n\n    .alert-danger .alert-link {\n        color: #843534\n    }\n\n@-webkit-keyframes progress-bar-stripes {\n    from {\n        background-position: 40px 0\n    }\n\n    to {\n        background-position: 0 0\n    }\n}\n\n@-o-keyframes progress-bar-stripes {\n    from {\n        background-position: 40px 0\n    }\n\n    to {\n        background-position: 0 0\n    }\n}\n\n@keyframes progress-bar-stripes {\n    from {\n        background-position: 40px 0\n    }\n\n    to {\n        background-position: 0 0\n    }\n}\n\n.progress {\n    height: 20px;\n    margin-bottom: 20px;\n    overflow: hidden;\n    background-color: #f5f5f5;\n    border-radius: 4px;\n    -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);\n    box-shadow: inset 0 1px 2px rgba(0,0,0,.1)\n}\n\n.progress-bar {\n    float: left;\n    width: 0%;\n    height: 100%;\n    font-size: 12px;\n    line-height: 20px;\n    color: #fff;\n    text-align: center;\n    background-color: #337ab7;\n    -webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);\n    box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);\n    -webkit-transition: width .6s;\n    -o-transition: width .6s;\n    transition: width .6s\n}\n\n.progress-bar-striped, .progress-striped .progress-bar {\n    background-image: -webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: -o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    -webkit-background-size: 40px 40px;\n    background-size: 40px 40px\n}\n\n.progress-bar.active, .progress.active .progress-bar {\n    -webkit-animation: 2s linear infinite progress-bar-stripes;\n    -o-animation: 2s linear infinite progress-bar-stripes;\n    animation: 2s linear infinite progress-bar-stripes\n}\n\n.progress-bar-success {\n    background-color: #5cb85c\n}\n\n.progress-striped .progress-bar-success {\n    background-image: -webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: -o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)\n}\n\n.progress-bar-info {\n    background-color: #5bc0de\n}\n\n.progress-striped .progress-bar-info {\n    background-image: -webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: -o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)\n}\n\n.progress-bar-warning {\n    background-color: #f0ad4e\n}\n\n.progress-striped .progress-bar-warning {\n    background-image: -webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: -o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)\n}\n\n.progress-bar-danger {\n    background-color: #d9534f\n}\n\n.progress-striped .progress-bar-danger {\n    background-image: -webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: -o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);\n    background-image: linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)\n}\n\n.media {\n    margin-top: 15px\n}\n\n    .media:first-child {\n        margin-top: 0\n    }\n\n.media, .media-body {\n    overflow: hidden;\n    zoom: 1\n}\n\n.media-body {\n    width: 10000px\n}\n\n.media-object {\n    display: block\n}\n\n    .media-object.img-thumbnail {\n        max-width: none\n    }\n\n.media-right, .media > .pull-right {\n    padding-left: 10px\n}\n\n.media-left, .media > .pull-left {\n    padding-right: 10px\n}\n\n.media-body, .media-left, .media-right {\n    display: table-cell;\n    vertical-align: top\n}\n\n.media-middle {\n    vertical-align: middle\n}\n\n.media-bottom {\n    vertical-align: bottom\n}\n\n.media-heading {\n    margin-top: 0;\n    margin-bottom: 5px\n}\n\n.media-list {\n    padding-left: 0;\n    list-style: none\n}\n\n.list-group {\n    padding-left: 0;\n    margin-bottom: 20px\n}\n\n.list-group-item {\n    position: relative;\n    display: block;\n    padding: 10px 15px;\n    margin-bottom: -1px;\n    background-color: #fff;\n    border: 1px solid #ddd\n}\n\n    .list-group-item:first-child {\n        border-top-left-radius: 4px;\n        border-top-right-radius: 4px\n    }\n\n    .list-group-item:last-child {\n        margin-bottom: 0;\n        border-bottom-right-radius: 4px;\n        border-bottom-left-radius: 4px\n    }\n\n    .list-group-item.disabled, .list-group-item.disabled:focus, .list-group-item.disabled:hover {\n        color: #777;\n        cursor: not-allowed;\n        background-color: #eee\n    }\n\n        .list-group-item.disabled .list-group-item-heading, .list-group-item.disabled:focus .list-group-item-heading, .list-group-item.disabled:hover .list-group-item-heading {\n            color: inherit\n        }\n\n        .list-group-item.disabled .list-group-item-text, .list-group-item.disabled:focus .list-group-item-text, .list-group-item.disabled:hover .list-group-item-text {\n            color: #777\n        }\n\n    .list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover {\n        z-index: 2;\n        color: #fff;\n        background-color: #337ab7;\n        border-color: #337ab7\n    }\n\n        .list-group-item.active .list-group-item-heading, .list-group-item.active .list-group-item-heading > .small, .list-group-item.active .list-group-item-heading > small, .list-group-item.active:focus .list-group-item-heading, .list-group-item.active:focus .list-group-item-heading > .small, .list-group-item.active:focus .list-group-item-heading > small, .list-group-item.active:hover .list-group-item-heading, .list-group-item.active:hover .list-group-item-heading > .small, .list-group-item.active:hover .list-group-item-heading > small {\n            color: inherit\n        }\n\n        .list-group-item.active .list-group-item-text, .list-group-item.active:focus .list-group-item-text, .list-group-item.active:hover .list-group-item-text {\n            color: #c7ddef\n        }\n\na.list-group-item, button.list-group-item {\n    color: #555\n}\n\n    a.list-group-item .list-group-item-heading, button.list-group-item .list-group-item-heading {\n        color: #333\n    }\n\n    a.list-group-item:focus, a.list-group-item:hover, button.list-group-item:focus, button.list-group-item:hover {\n        color: #555;\n        text-decoration: none;\n        background-color: #f5f5f5\n    }\n\nbutton.list-group-item {\n    width: 100%;\n    text-align: left\n}\n\n.list-group-item-success {\n    color: #3c763d;\n    background-color: #dff0d8\n}\n\na.list-group-item-success, button.list-group-item-success {\n    color: #3c763d\n}\n\n    a.list-group-item-success .list-group-item-heading, button.list-group-item-success .list-group-item-heading {\n        color: inherit\n    }\n\n    a.list-group-item-success:focus, a.list-group-item-success:hover, button.list-group-item-success:focus, button.list-group-item-success:hover {\n        color: #3c763d;\n        background-color: #d0e9c6\n    }\n\n    a.list-group-item-success.active, a.list-group-item-success.active:focus, a.list-group-item-success.active:hover, button.list-group-item-success.active, button.list-group-item-success.active:focus, button.list-group-item-success.active:hover {\n        color: #fff;\n        background-color: #3c763d;\n        border-color: #3c763d\n    }\n\n.list-group-item-info {\n    color: #31708f;\n    background-color: #d9edf7\n}\n\na.list-group-item-info, button.list-group-item-info {\n    color: #31708f\n}\n\n    a.list-group-item-info .list-group-item-heading, button.list-group-item-info .list-group-item-heading {\n        color: inherit\n    }\n\n    a.list-group-item-info:focus, a.list-group-item-info:hover, button.list-group-item-info:focus, button.list-group-item-info:hover {\n        color: #31708f;\n        background-color: #c4e3f3\n    }\n\n    a.list-group-item-info.active, a.list-group-item-info.active:focus, a.list-group-item-info.active:hover, button.list-group-item-info.active, button.list-group-item-info.active:focus, button.list-group-item-info.active:hover {\n        color: #fff;\n        background-color: #31708f;\n        border-color: #31708f\n    }\n\n.list-group-item-warning {\n    color: #8a6d3b;\n    background-color: #fcf8e3\n}\n\na.list-group-item-warning, button.list-group-item-warning {\n    color: #8a6d3b\n}\n\n    a.list-group-item-warning .list-group-item-heading, button.list-group-item-warning .list-group-item-heading {\n        color: inherit\n    }\n\n    a.list-group-item-warning:focus, a.list-group-item-warning:hover, button.list-group-item-warning:focus, button.list-group-item-warning:hover {\n        color: #8a6d3b;\n        background-color: #faf2cc\n    }\n\n    a.list-group-item-warning.active, a.list-group-item-warning.active:focus, a.list-group-item-warning.active:hover, button.list-group-item-warning.active, button.list-group-item-warning.active:focus, button.list-group-item-warning.active:hover {\n        color: #fff;\n        background-color: #8a6d3b;\n        border-color: #8a6d3b\n    }\n\n.list-group-item-danger {\n    color: #a94442;\n    background-color: #f2dede\n}\n\na.list-group-item-danger, button.list-group-item-danger {\n    color: #a94442\n}\n\n    a.list-group-item-danger .list-group-item-heading, button.list-group-item-danger .list-group-item-heading {\n        color: inherit\n    }\n\n    a.list-group-item-danger:focus, a.list-group-item-danger:hover, button.list-group-item-danger:focus, button.list-group-item-danger:hover {\n        color: #a94442;\n        background-color: #ebcccc\n    }\n\n    a.list-group-item-danger.active, a.list-group-item-danger.active:focus, a.list-group-item-danger.active:hover, button.list-group-item-danger.active, button.list-group-item-danger.active:focus, button.list-group-item-danger.active:hover {\n        color: #fff;\n        background-color: #a94442;\n        border-color: #a94442\n    }\n\n.list-group-item-heading {\n    margin-top: 0;\n    margin-bottom: 5px\n}\n\n.list-group-item-text {\n    margin-bottom: 0;\n    line-height: 1.3\n}\n\n.panel {\n    margin-bottom: 20px;\n    background-color: #fff;\n    border: 1px solid transparent;\n    border-radius: 4px;\n    -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05);\n    box-shadow: 0 1px 1px rgba(0,0,0,.05)\n}\n\n.panel-body {\n    padding: 15px\n}\n\n.panel-heading {\n    padding: 10px 15px;\n    border-bottom: 1px solid transparent;\n    border-top-left-radius: 3px;\n    border-top-right-radius: 3px\n}\n\n    .panel-heading > .dropdown .dropdown-toggle {\n        color: inherit\n    }\n\n.panel-title {\n    margin-top: 0;\n    margin-bottom: 0;\n    font-size: 16px;\n    color: inherit\n}\n\n    .panel-title > .small, .panel-title > .small > a, .panel-title > a, .panel-title > small, .panel-title > small > a {\n        color: inherit\n    }\n\n.panel-footer {\n    padding: 10px 15px;\n    background-color: #f5f5f5;\n    border-top: 1px solid #ddd;\n    border-bottom-right-radius: 3px;\n    border-bottom-left-radius: 3px\n}\n\n.panel > .list-group, .panel > .panel-collapse > .list-group {\n    margin-bottom: 0\n}\n\n    .panel > .list-group .list-group-item, .panel > .panel-collapse > .list-group .list-group-item {\n        border-width: 1px 0;\n        border-radius: 0\n    }\n\n    .panel > .list-group:first-child .list-group-item:first-child, .panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n        border-top: 0;\n        border-top-left-radius: 3px;\n        border-top-right-radius: 3px\n    }\n\n    .panel > .list-group:last-child .list-group-item:last-child, .panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n        border-bottom: 0;\n        border-bottom-right-radius: 3px;\n        border-bottom-left-radius: 3px\n    }\n\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n    border-top-left-radius: 0;\n    border-top-right-radius: 0\n}\n\n.list-group + .panel-footer, .panel-heading + .list-group .list-group-item:first-child {\n    border-top-width: 0\n}\n\n.panel > .panel-collapse > .table, .panel > .table, .panel > .table-responsive > .table {\n    margin-bottom: 0\n}\n\n    .panel > .panel-collapse > .table caption, .panel > .table caption, .panel > .table-responsive > .table caption {\n        padding-right: 15px;\n        padding-left: 15px\n    }\n\n    .panel > .table-responsive:first-child > .table:first-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, .panel > .table:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child, .panel > .table:first-child > thead:first-child > tr:first-child {\n        border-top-left-radius: 3px;\n        border-top-right-radius: 3px\n    }\n\n        .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, .panel > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table:first-child > thead:first-child > tr:first-child th:first-child {\n            border-top-left-radius: 3px\n        }\n\n        .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, .panel > .table:first-child > thead:first-child > tr:first-child td:last-child, .panel > .table:first-child > thead:first-child > tr:first-child th:last-child {\n            border-top-right-radius: 3px\n        }\n\n    .panel > .table-responsive:last-child > .table:last-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child, .panel > .table:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child {\n        border-bottom-right-radius: 3px;\n        border-bottom-left-radius: 3px\n    }\n\n        .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child, .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n            border-bottom-left-radius: 3px\n        }\n\n        .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n            border-bottom-right-radius: 3px\n        }\n\n    .panel > .panel-body + .table, .panel > .panel-body + .table-responsive, .panel > .table + .panel-body, .panel > .table-responsive + .panel-body {\n        border-top: 1px solid #ddd\n    }\n\n    .panel > .table > tbody:first-child > tr:first-child td, .panel > .table > tbody:first-child > tr:first-child th {\n        border-top: 0\n    }\n\n.panel > .table-bordered, .panel > .table-responsive > .table-bordered {\n    border: 0\n}\n\n    .panel > .table-bordered > tbody > tr > td:first-child, .panel > .table-bordered > tbody > tr > th:first-child, .panel > .table-bordered > tfoot > tr > td:first-child, .panel > .table-bordered > tfoot > tr > th:first-child, .panel > .table-bordered > thead > tr > td:first-child, .panel > .table-bordered > thead > tr > th:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, .panel > .table-responsive > .table-bordered > thead > tr > td:first-child, .panel > .table-responsive > .table-bordered > thead > tr > th:first-child {\n        border-left: 0\n    }\n\n    .panel > .table-bordered > tbody > tr > td:last-child, .panel > .table-bordered > tbody > tr > th:last-child, .panel > .table-bordered > tfoot > tr > td:last-child, .panel > .table-bordered > tfoot > tr > th:last-child, .panel > .table-bordered > thead > tr > td:last-child, .panel > .table-bordered > thead > tr > th:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, .panel > .table-responsive > .table-bordered > thead > tr > td:last-child, .panel > .table-responsive > .table-bordered > thead > tr > th:last-child {\n        border-right: 0\n    }\n\n    .panel > .table-bordered > tbody > tr:first-child > td, .panel > .table-bordered > tbody > tr:first-child > th, .panel > .table-bordered > tbody > tr:last-child > td, .panel > .table-bordered > tbody > tr:last-child > th, .panel > .table-bordered > tfoot > tr:last-child > td, .panel > .table-bordered > tfoot > tr:last-child > th, .panel > .table-bordered > thead > tr:first-child > td, .panel > .table-bordered > thead > tr:first-child > th, .panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:first-child > th, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, .panel > .table-responsive > .table-bordered > thead > tr:first-child > td, .panel > .table-responsive > .table-bordered > thead > tr:first-child > th {\n        border-bottom: 0\n    }\n\n.panel > .table-responsive {\n    margin-bottom: 0;\n    border: 0\n}\n\n.panel-group {\n    margin-bottom: 20px\n}\n\n    .panel-group .panel {\n        margin-bottom: 0;\n        border-radius: 4px\n    }\n\n        .panel-group .panel + .panel {\n            margin-top: 5px\n        }\n\n    .panel-group .panel-heading {\n        border-bottom: 0\n    }\n\n        .panel-group .panel-heading + .panel-collapse > .list-group, .panel-group .panel-heading + .panel-collapse > .panel-body {\n            border-top: 1px solid #ddd\n        }\n\n    .panel-group .panel-footer {\n        border-top: 0\n    }\n\n        .panel-group .panel-footer + .panel-collapse .panel-body {\n            border-bottom: 1px solid #ddd\n        }\n\n.panel-default {\n    border-color: #ddd\n}\n\n    .panel-default > .panel-heading {\n        color: #333;\n        background-color: #f5f5f5;\n        border-color: #ddd\n    }\n\n        .panel-default > .panel-heading + .panel-collapse > .panel-body {\n            border-top-color: #ddd\n        }\n\n        .panel-default > .panel-heading .badge {\n            color: #f5f5f5;\n            background-color: #333\n        }\n\n    .panel-default > .panel-footer + .panel-collapse > .panel-body {\n        border-bottom-color: #ddd\n    }\n\n.panel-primary {\n    border-color: #337ab7\n}\n\n    .panel-primary > .panel-heading {\n        color: #fff;\n        background-color: #337ab7;\n        border-color: #337ab7\n    }\n\n        .panel-primary > .panel-heading + .panel-collapse > .panel-body {\n            border-top-color: #337ab7\n        }\n\n        .panel-primary > .panel-heading .badge {\n            color: #337ab7;\n            background-color: #fff\n        }\n\n    .panel-primary > .panel-footer + .panel-collapse > .panel-body {\n        border-bottom-color: #337ab7\n    }\n\n.panel-success {\n    border-color: #d6e9c6\n}\n\n    .panel-success > .panel-heading {\n        color: #3c763d;\n        background-color: #dff0d8;\n        border-color: #d6e9c6\n    }\n\n        .panel-success > .panel-heading + .panel-collapse > .panel-body {\n            border-top-color: #d6e9c6\n        }\n\n        .panel-success > .panel-heading .badge {\n            color: #dff0d8;\n            background-color: #3c763d\n        }\n\n    .panel-success > .panel-footer + .panel-collapse > .panel-body {\n        border-bottom-color: #d6e9c6\n    }\n\n.panel-info {\n    border-color: #bce8f1\n}\n\n    .panel-info > .panel-heading {\n        color: #31708f;\n        background-color: #d9edf7;\n        border-color: #bce8f1\n    }\n\n        .panel-info > .panel-heading + .panel-collapse > .panel-body {\n            border-top-color: #bce8f1\n        }\n\n        .panel-info > .panel-heading .badge {\n            color: #d9edf7;\n            background-color: #31708f\n        }\n\n    .panel-info > .panel-footer + .panel-collapse > .panel-body {\n        border-bottom-color: #bce8f1\n    }\n\n.panel-warning {\n    border-color: #faebcc\n}\n\n    .panel-warning > .panel-heading {\n        color: #8a6d3b;\n        background-color: #fcf8e3;\n        border-color: #faebcc\n    }\n\n        .panel-warning > .panel-heading + .panel-collapse > .panel-body {\n            border-top-color: #faebcc\n        }\n\n        .panel-warning > .panel-heading .badge {\n            color: #fcf8e3;\n            background-color: #8a6d3b\n        }\n\n    .panel-warning > .panel-footer + .panel-collapse > .panel-body {\n        border-bottom-color: #faebcc\n    }\n\n.panel-danger {\n    border-color: #ebccd1\n}\n\n    .panel-danger > .panel-heading {\n        color: #a94442;\n        background-color: #f2dede;\n        border-color: #ebccd1\n    }\n\n        .panel-danger > .panel-heading + .panel-collapse > .panel-body {\n            border-top-color: #ebccd1\n        }\n\n        .panel-danger > .panel-heading .badge {\n            color: #f2dede;\n            background-color: #a94442\n        }\n\n    .panel-danger > .panel-footer + .panel-collapse > .panel-body {\n        border-bottom-color: #ebccd1\n    }\n\n.embed-responsive {\n    position: relative;\n    display: block;\n    height: 0;\n    padding: 0;\n    overflow: hidden\n}\n\n    .embed-responsive .embed-responsive-item, .embed-responsive embed, .embed-responsive iframe, .embed-responsive object, .embed-responsive video {\n        position: absolute;\n        top: 0;\n        bottom: 0;\n        left: 0;\n        width: 100%;\n        height: 100%;\n        border: 0\n    }\n\n.embed-responsive-16by9 {\n    padding-bottom: 56.25%\n}\n\n.embed-responsive-4by3 {\n    padding-bottom: 75%\n}\n\n.well {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.05);\n    box-shadow: inset 0 1px 1px rgba(0,0,0,.05)\n}\n\n    .well blockquote {\n        border-color: rgba(0,0,0,.15)\n    }\n\n.well-lg {\n    padding: 24px;\n    border-radius: 6px\n}\n\n.well-sm {\n    padding: 9px;\n    border-radius: 3px\n}\n\n.close {\n    float: right;\n    font-size: 21px;\n    font-weight: 700;\n    line-height: 1;\n    color: #000;\n    text-shadow: 0 1px 0 #fff;\n    opacity: .2\n}\n\n    .close:focus, .close:hover {\n        color: #000;\n        text-decoration: none;\n        cursor: pointer;\n        opacity: .5\n    }\n\nbutton.close {\n    padding: 0;\n    cursor: pointer;\n    background: 0 0;\n    border: 0;\n    -webkit-appearance: none;\n    -moz-appearance: none;\n    appearance: none\n}\n\n.modal-open {\n    overflow: hidden\n}\n\n.modal {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 1050;\n    display: none;\n    overflow: hidden;\n    -webkit-overflow-scrolling: touch;\n    outline: 0\n}\n\n    .modal.fade .modal-dialog {\n        -webkit-transform: translate(0,-25%);\n        -ms-transform: translate(0,-25%);\n        -o-transform: translate(0,-25%);\n        transform: translate(0,-25%);\n        -webkit-transition: -webkit-transform .3s ease-out;\n        -o-transition: -o-transform .3s ease-out;\n        transition: transform .3s ease-out;\n        transition: transform .3s ease-out,-webkit-transform .3s ease-out,-o-transform .3s ease-out\n    }\n\n    .modal.in .modal-dialog {\n        -webkit-transform: translate(0,0);\n        -ms-transform: translate(0,0);\n        -o-transform: translate(0,0);\n        transform: translate(0,0)\n    }\n\n.modal-open .modal {\n    overflow-x: hidden;\n    overflow-y: auto\n}\n\n.modal-dialog {\n    position: relative;\n    width: auto;\n    margin: 10px\n}\n\n.modal-content {\n    position: relative;\n    background-color: #fff;\n    background-clip: padding-box;\n    border: 1px solid rgba(0,0,0,.2);\n    border-radius: 6px;\n    -webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);\n    box-shadow: 0 3px 9px rgba(0,0,0,.5);\n    outline: 0\n}\n\n.modal-backdrop {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 1040;\n    background-color: #000\n}\n\n    .modal-backdrop.fade {\n        opacity: 0\n    }\n\n    .modal-backdrop.in {\n        opacity: .5\n    }\n\n.modal-header {\n    padding: 15px;\n    border-bottom: 1px solid #e5e5e5\n}\n\n    .modal-header .close {\n        margin-top: -2px\n    }\n\n.modal-title {\n    margin: 0;\n    line-height: 1.42857143\n}\n\n.modal-body {\n    position: relative;\n    padding: 15px\n}\n\n.modal-footer {\n    padding: 15px;\n    text-align: right;\n    border-top: 1px solid #e5e5e5\n}\n\n    .modal-footer .btn + .btn {\n        margin-bottom: 0;\n        margin-left: 5px\n    }\n\n    .modal-footer .btn-group .btn + .btn {\n        margin-left: -1px\n    }\n\n    .modal-footer .btn-block + .btn-block {\n        margin-left: 0\n    }\n\n.modal-scrollbar-measure {\n    position: absolute;\n    top: -9999px;\n    width: 50px;\n    height: 50px;\n    overflow: scroll\n}\n\n@media (min-width:768px) {\n    .modal-dialog {\n        width: 600px;\n        margin: 30px auto\n    }\n\n    .modal-content {\n        -webkit-box-shadow: 0 5px 15px rgba(0,0,0,.5);\n        box-shadow: 0 5px 15px rgba(0,0,0,.5)\n    }\n\n    .modal-sm {\n        width: 300px\n    }\n}\n\n@media (min-width:992px) {\n    .modal-lg {\n        width: 900px\n    }\n}\n\n.tooltip {\n    position: absolute;\n    z-index: 1070;\n    display: block;\n    font-family: \"Helvetica Neue\",Helvetica,Arial,sans-serif;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 1.42857143;\n    line-break: auto;\n    text-align: left;\n    text-align: start;\n    text-decoration: none;\n    text-shadow: none;\n    text-transform: none;\n    letter-spacing: normal;\n    word-break: normal;\n    word-spacing: normal;\n    word-wrap: normal;\n    white-space: normal;\n    font-size: 12px;\n    opacity: 0\n}\n\n    .tooltip.in {\n        opacity: .9\n    }\n\n    .tooltip.top {\n        padding: 5px 0;\n        margin-top: -3px\n    }\n\n    .tooltip.right {\n        padding: 0 5px;\n        margin-left: 3px\n    }\n\n    .tooltip.bottom {\n        padding: 5px 0;\n        margin-top: 3px\n    }\n\n    .tooltip.left {\n        padding: 0 5px;\n        margin-left: -3px\n    }\n\n    .tooltip.top .tooltip-arrow {\n        bottom: 0;\n        left: 50%;\n        margin-left: -5px;\n        border-width: 5px 5px 0;\n        border-top-color: #000\n    }\n\n    .tooltip.top-left .tooltip-arrow {\n        right: 5px;\n        bottom: 0;\n        margin-bottom: -5px;\n        border-width: 5px 5px 0;\n        border-top-color: #000\n    }\n\n    .tooltip.top-right .tooltip-arrow {\n        bottom: 0;\n        left: 5px;\n        margin-bottom: -5px;\n        border-width: 5px 5px 0;\n        border-top-color: #000\n    }\n\n    .tooltip.right .tooltip-arrow {\n        top: 50%;\n        left: 0;\n        margin-top: -5px;\n        border-width: 5px 5px 5px 0;\n        border-right-color: #000\n    }\n\n    .tooltip.left .tooltip-arrow {\n        top: 50%;\n        right: 0;\n        margin-top: -5px;\n        border-width: 5px 0 5px 5px;\n        border-left-color: #000\n    }\n\n    .tooltip.bottom .tooltip-arrow {\n        top: 0;\n        left: 50%;\n        margin-left: -5px;\n        border-width: 0 5px 5px;\n        border-bottom-color: #000\n    }\n\n    .tooltip.bottom-left .tooltip-arrow {\n        top: 0;\n        right: 5px;\n        margin-top: -5px;\n        border-width: 0 5px 5px;\n        border-bottom-color: #000\n    }\n\n    .tooltip.bottom-right .tooltip-arrow {\n        top: 0;\n        left: 5px;\n        margin-top: -5px;\n        border-width: 0 5px 5px;\n        border-bottom-color: #000\n    }\n\n.tooltip-inner {\n    max-width: 200px;\n    padding: 3px 8px;\n    color: #fff;\n    text-align: center;\n    background-color: #000;\n    border-radius: 4px\n}\n\n.tooltip-arrow {\n    position: absolute;\n    width: 0;\n    height: 0;\n    border-color: transparent;\n    border-style: solid\n}\n\n.popover {\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: 1060;\n    display: none;\n    max-width: 276px;\n    padding: 1px;\n    font-family: \"Helvetica Neue\",Helvetica,Arial,sans-serif;\n    font-style: normal;\n    font-weight: 400;\n    line-height: 1.42857143;\n    line-break: auto;\n    text-align: left;\n    text-align: start;\n    text-decoration: none;\n    text-shadow: none;\n    text-transform: none;\n    letter-spacing: normal;\n    word-break: normal;\n    word-spacing: normal;\n    word-wrap: normal;\n    white-space: normal;\n    font-size: 14px;\n    background-color: #fff;\n    background-clip: padding-box;\n    border: 1px solid rgba(0,0,0,.2);\n    border-radius: 6px;\n    -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);\n    box-shadow: 0 5px 10px rgba(0,0,0,.2)\n}\n\n    .popover.top {\n        margin-top: -10px\n    }\n\n    .popover.right {\n        margin-left: 10px\n    }\n\n    .popover.bottom {\n        margin-top: 10px\n    }\n\n    .popover.left {\n        margin-left: -10px\n    }\n\n    .popover > .arrow {\n        border-width: 11px\n    }\n\n        .popover > .arrow, .popover > .arrow:after {\n            position: absolute;\n            display: block;\n            width: 0;\n            height: 0;\n            border-color: transparent;\n            border-style: solid\n        }\n\n            .popover > .arrow:after {\n                content: \"\";\n                border-width: 10px\n            }\n\n    .popover.top > .arrow {\n        bottom: -11px;\n        left: 50%;\n        margin-left: -11px;\n        border-top-color: rgba(0,0,0,.25);\n        border-bottom-width: 0\n    }\n\n        .popover.top > .arrow:after {\n            bottom: 1px;\n            margin-left: -10px;\n            content: \" \";\n            border-top-color: #fff;\n            border-bottom-width: 0\n        }\n\n    .popover.right > .arrow {\n        top: 50%;\n        left: -11px;\n        margin-top: -11px;\n        border-right-color: rgba(0,0,0,.25);\n        border-left-width: 0\n    }\n\n        .popover.right > .arrow:after {\n            bottom: -10px;\n            left: 1px;\n            content: \" \";\n            border-right-color: #fff;\n            border-left-width: 0\n        }\n\n    .popover.bottom > .arrow {\n        top: -11px;\n        left: 50%;\n        margin-left: -11px;\n        border-top-width: 0;\n        border-bottom-color: rgba(0,0,0,.25)\n    }\n\n        .popover.bottom > .arrow:after {\n            top: 1px;\n            margin-left: -10px;\n            content: \" \";\n            border-top-width: 0;\n            border-bottom-color: #fff\n        }\n\n    .popover.left > .arrow {\n        top: 50%;\n        right: -11px;\n        margin-top: -11px;\n        border-right-width: 0;\n        border-left-color: rgba(0,0,0,.25)\n    }\n\n        .popover.left > .arrow:after {\n            right: 1px;\n            bottom: -10px;\n            content: \" \";\n            border-right-width: 0;\n            border-left-color: #fff\n        }\n\n.popover-title {\n    padding: 8px 14px;\n    margin: 0;\n    font-size: 14px;\n    background-color: #f7f7f7;\n    border-bottom: 1px solid #ebebeb;\n    border-radius: 5px 5px 0 0\n}\n\n.popover-content {\n    padding: 9px 14px\n}\n\n.carousel {\n    position: relative\n}\n\n.carousel-inner {\n    position: relative;\n    width: 100%;\n    overflow: hidden\n}\n\n    .carousel-inner > .item {\n        position: relative;\n        display: none;\n        -webkit-transition: left .6s ease-in-out;\n        -o-transition: left .6s ease-in-out;\n        transition: left .6s ease-in-out\n    }\n\n        .carousel-inner > .item > a > img, .carousel-inner > .item > img {\n            line-height: 1\n        }\n\n@media all and (transform-3d),(-webkit-transform-3d) {\n    .carousel-inner > .item {\n        -webkit-transition: -webkit-transform .6s ease-in-out;\n        -o-transition: -o-transform .6s ease-in-out;\n        transition: transform .6s ease-in-out;\n        transition: transform .6s ease-in-out,-webkit-transform .6s ease-in-out,-o-transform .6s ease-in-out;\n        -webkit-backface-visibility: hidden;\n        backface-visibility: hidden;\n        -webkit-perspective: 1000px;\n        perspective: 1000px\n    }\n\n        .carousel-inner > .item.active.right, .carousel-inner > .item.next {\n            -webkit-transform: translate3d(100%,0,0);\n            transform: translate3d(100%,0,0);\n            left: 0\n        }\n\n        .carousel-inner > .item.active.left, .carousel-inner > .item.prev {\n            -webkit-transform: translate3d(-100%,0,0);\n            transform: translate3d(-100%,0,0);\n            left: 0\n        }\n\n            .carousel-inner > .item.active, .carousel-inner > .item.next.left, .carousel-inner > .item.prev.right {\n                -webkit-transform: translate3d(0,0,0);\n                transform: translate3d(0,0,0);\n                left: 0\n            }\n}\n\n.carousel-inner > .active, .carousel-inner > .next, .carousel-inner > .prev {\n    display: block\n}\n\n.carousel-inner > .active {\n    left: 0\n}\n\n.carousel-inner > .next, .carousel-inner > .prev {\n    position: absolute;\n    top: 0;\n    width: 100%\n}\n\n.carousel-inner > .next {\n    left: 100%\n}\n\n.carousel-inner > .prev {\n    left: -100%\n}\n\n    .carousel-inner > .next.left, .carousel-inner > .prev.right {\n        left: 0\n    }\n\n.carousel-inner > .active.left {\n    left: -100%\n}\n\n.carousel-inner > .active.right {\n    left: 100%\n}\n\n.carousel-control {\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    width: 15%;\n    font-size: 20px;\n    color: #fff;\n    text-align: center;\n    text-shadow: 0 1px 2px rgba(0,0,0,.6);\n    background-color: rgba(0,0,0,0);\n    opacity: .5\n}\n\n    .carousel-control.left {\n        background-image: -webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);\n        background-image: -o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);\n        background-image: -webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));\n        background-image: linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);\n        background-repeat: repeat-x\n    }\n\n    .carousel-control.right {\n        right: 0;\n        left: auto;\n        background-image: -webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);\n        background-image: -o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);\n        background-image: -webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));\n        background-image: linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);\n        background-repeat: repeat-x\n    }\n\n    .carousel-control:focus, .carousel-control:hover {\n        color: #fff;\n        text-decoration: none;\n        outline: 0;\n        opacity: .9\n    }\n\n    .carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next, .carousel-control .icon-prev {\n        position: absolute;\n        top: 50%;\n        z-index: 5;\n        display: inline-block;\n        margin-top: -10px\n    }\n\n    .carousel-control .glyphicon-chevron-left, .carousel-control .icon-prev {\n        left: 50%;\n        margin-left: -10px\n    }\n\n    .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next {\n        right: 50%;\n        margin-right: -10px\n    }\n\n    .carousel-control .icon-next, .carousel-control .icon-prev {\n        width: 20px;\n        height: 20px;\n        font-family: serif;\n        line-height: 1\n    }\n\n        .carousel-control .icon-prev:before {\n            content: \"\\2039\"\n        }\n\n        .carousel-control .icon-next:before {\n            content: \"\\203a\"\n        }\n\n.carousel-indicators {\n    position: absolute;\n    bottom: 10px;\n    left: 50%;\n    z-index: 15;\n    width: 60%;\n    padding-left: 0;\n    margin-left: -30%;\n    text-align: center;\n    list-style: none\n}\n\n    .carousel-indicators li {\n        display: inline-block;\n        width: 10px;\n        height: 10px;\n        margin: 1px;\n        text-indent: -999px;\n        cursor: pointer;\n        background-color: rgba(0,0,0,0);\n        border: 1px solid #fff;\n        border-radius: 10px\n    }\n\n    .carousel-indicators .active {\n        width: 12px;\n        height: 12px;\n        margin: 0;\n        background-color: #fff\n    }\n\n.carousel-caption {\n    position: absolute;\n    right: 15%;\n    bottom: 20px;\n    left: 15%;\n    z-index: 10;\n    padding-top: 20px;\n    padding-bottom: 20px;\n    color: #fff;\n    text-align: center;\n    text-shadow: 0 1px 2px rgba(0,0,0,.6)\n}\n\n    .carousel-caption .btn {\n        text-shadow: none\n    }\n\n@media screen and (min-width:768px) {\n    .carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next, .carousel-control .icon-prev {\n        width: 30px;\n        height: 30px;\n        margin-top: -10px;\n        font-size: 30px\n    }\n\n    .carousel-control .glyphicon-chevron-left, .carousel-control .icon-prev {\n        margin-left: -10px\n    }\n\n    .carousel-control .glyphicon-chevron-right, .carousel-control .icon-next {\n        margin-right: -10px\n    }\n\n    .carousel-caption {\n        right: 20%;\n        left: 20%;\n        padding-bottom: 30px\n    }\n\n    .carousel-indicators {\n        bottom: 20px\n    }\n}\n\n.btn-group-vertical > .btn-group:after, .btn-group-vertical > .btn-group:before, .btn-toolbar:after, .btn-toolbar:before, .clearfix:after, .clearfix:before, .container-fluid:after, .container-fluid:before, .container:after, .container:before, .dl-horizontal dd:after, .dl-horizontal dd:before, .form-horizontal .form-group:after, .form-horizontal .form-group:before, .modal-footer:after, .modal-footer:before, .modal-header:after, .modal-header:before, .nav:after, .nav:before, .navbar-collapse:after, .navbar-collapse:before, .navbar-header:after, .navbar-header:before, .navbar:after, .navbar:before, .pager:after, .pager:before, .panel-body:after, .panel-body:before, .row:after, .row:before {\n    display: table;\n    content: \" \"\n}\n\n.btn-group-vertical > .btn-group:after, .btn-toolbar:after, .clearfix:after, .container-fluid:after, .container:after, .dl-horizontal dd:after, .form-horizontal .form-group:after, .modal-footer:after, .modal-header:after, .nav:after, .navbar-collapse:after, .navbar-header:after, .navbar:after, .pager:after, .panel-body:after, .row:after {\n    clear: both\n}\n\n.center-block {\n    display: block;\n    margin-right: auto;\n    margin-left: auto\n}\n\n.pull-right {\n    float: right !important\n}\n\n.pull-left {\n    float: left !important\n}\n\n.hide {\n    display: none !important\n}\n\n.show {\n    display: block !important\n}\n\n.invisible {\n    visibility: hidden\n}\n\n.text-hide {\n    font: 0/0 a;\n    color: transparent;\n    text-shadow: none;\n    background-color: transparent;\n    border: 0\n}\n\n.hidden {\n    display: none !important\n}\n\n.affix {\n    position: fixed\n}\n\n@-ms-viewport {\n    width: device-width\n}\n\n.visible-lg, .visible-lg-block, .visible-lg-inline, .visible-lg-inline-block, .visible-md, .visible-md-block, .visible-md-inline, .visible-md-inline-block, .visible-sm, .visible-sm-block, .visible-sm-inline, .visible-sm-inline-block, .visible-xs, .visible-xs-block, .visible-xs-inline, .visible-xs-inline-block {\n    display: none !important\n}\n\n@media (max-width:767px) {\n    .visible-xs {\n        display: block !important\n    }\n\n    table.visible-xs {\n        display: table !important\n    }\n\n    tr.visible-xs {\n        display: table-row !important\n    }\n\n    td.visible-xs, th.visible-xs {\n        display: table-cell !important\n    }\n\n    .visible-xs-block {\n        display: block !important\n    }\n\n    .visible-xs-inline {\n        display: inline !important\n    }\n\n    .visible-xs-inline-block {\n        display: inline-block !important\n    }\n}\n\n@media (min-width:768px) and (max-width:991px) {\n    .visible-sm {\n        display: block !important\n    }\n\n    table.visible-sm {\n        display: table !important\n    }\n\n    tr.visible-sm {\n        display: table-row !important\n    }\n\n    td.visible-sm, th.visible-sm {\n        display: table-cell !important\n    }\n\n    .visible-sm-block {\n        display: block !important\n    }\n\n    .visible-sm-inline {\n        display: inline !important\n    }\n\n    .visible-sm-inline-block {\n        display: inline-block !important\n    }\n}\n\n@media (min-width:992px) and (max-width:1199px) {\n    .visible-md {\n        display: block !important\n    }\n\n    table.visible-md {\n        display: table !important\n    }\n\n    tr.visible-md {\n        display: table-row !important\n    }\n\n    td.visible-md, th.visible-md {\n        display: table-cell !important\n    }\n\n    .visible-md-block {\n        display: block !important\n    }\n\n    .visible-md-inline {\n        display: inline !important\n    }\n\n    .visible-md-inline-block {\n        display: inline-block !important\n    }\n}\n\n@media (min-width:1200px) {\n    .visible-lg {\n        display: block !important\n    }\n\n    table.visible-lg {\n        display: table !important\n    }\n\n    tr.visible-lg {\n        display: table-row !important\n    }\n\n    td.visible-lg, th.visible-lg {\n        display: table-cell !important\n    }\n\n    .visible-lg-block {\n        display: block !important\n    }\n\n    .visible-lg-inline {\n        display: inline !important\n    }\n\n    .visible-lg-inline-block {\n        display: inline-block !important\n    }\n\n    .hidden-lg {\n        display: none !important\n    }\n}\n\n@media (max-width:767px) {\n    .hidden-xs {\n        display: none !important\n    }\n}\n\n@media (min-width:768px) and (max-width:991px) {\n    .hidden-sm {\n        display: none !important\n    }\n}\n\n@media (min-width:992px) and (max-width:1199px) {\n    .hidden-md {\n        display: none !important\n    }\n}\n\n.visible-print {\n    display: none !important\n}\n\n@media print {\n    .visible-print {\n        display: block !important\n    }\n\n    table.visible-print {\n        display: table !important\n    }\n\n    tr.visible-print {\n        display: table-row !important\n    }\n\n    td.visible-print, th.visible-print {\n        display: table-cell !important\n    }\n}\n\n.visible-print-block {\n    display: none !important\n}\n\n@media print {\n    .visible-print-block {\n        display: block !important\n    }\n}\n\n.visible-print-inline {\n    display: none !important\n}\n\n@media print {\n    .visible-print-inline {\n        display: inline !important\n    }\n}\n\n.visible-print-inline-block {\n    display: none !important\n}\n\n@media print {\n    .visible-print-inline-block {\n        display: inline-block !important\n    }\n\n    .hidden-print {\n        display: none !important\n    }\n}\n\n.hljs {\n    display: block;\n    background: #fff;\n    padding: .5em;\n    color: #333;\n    overflow-x: auto\n}\n\n.hljs-comment, .hljs-meta {\n    color: #969896\n}\n\n.hljs-emphasis, .hljs-quote, .hljs-string, .hljs-strong, .hljs-template-variable, .hljs-variable {\n    color: #df5000\n}\n\n.hljs-keyword, .hljs-selector-tag, .hljs-type {\n    color: #a71d5d\n}\n\n.hljs-attribute, .hljs-bullet, .hljs-literal, .hljs-symbol {\n    color: #0086b3\n}\n\n.hljs-name, .hljs-section {\n    color: #63a35c\n}\n\n.hljs-tag {\n    color: #333\n}\n\n.hljs-attr, .hljs-selector-attr, .hljs-selector-class, .hljs-selector-id, .hljs-selector-pseudo, .hljs-title {\n    color: #795da3\n}\n\n.hljs-addition {\n    color: #55a532;\n    background-color: #eaffea\n}\n\n.hljs-deletion {\n    color: #bd2c00;\n    background-color: #ffecec\n}\n\n.hljs-link {\n    text-decoration: underline\n}\n\n/* COLOR VARIABLES*/\n:root {\n    --header-bg-color: #212121;\n    --header-ft-color: #fefefe;\n    --highlight-light: rgb(9, 105, 218);\n    --highlight-dark: rgb(9, 105, 218);\n    --accent-dim: #e0e0e0;\n    --accent-super-dim: #f3f3f3;\n    --font-color: rgb(31, 35, 40);\n    --toc-font-color: #222222;\n    --tab-hover-color: #444444;\n    --card-box-shadow: 0 1px 2px 0 rgba(61, 65, 68, 0.06), 0 1px 3px 1px rgba(61, 65, 68, 0.16);\n    --search-box-shadow: 0 1px 2px 0 rgba(41, 45, 48, 0.36), 0 1px 3px 1px rgba(41, 45, 48, 0.46);\n    --transition: 350ms;\n}\n\n\n\nbody {\n    background: white;\n    color: var(--font-color);\n    font-family: \"Roboto\", sans-serif;\n    line-height: 1.5;\n    font-size: 15px !important;\n    /*  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;*/\n    word-wrap: break-word;\n}\n\n    body div, body p, body ul {\n        color: var(--font-color);\n        font-family: \"Roboto\", sans-serif !important;\n        line-height: 1.5 !important;\n        font-size: 15px !important;\n        /*  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;*/\n        word-wrap: break-word;\n    }\n\nbody, p, blockquote, ul, ol, dl, table, pre, code, tr {\n    color: var(--font-color);\n}\n\n/* HIGHLIGHT COLOR */\np {\n    margin: 0 0 12px;\n    /*text-align: justify;*/\n}\n\nbutton,\na {\n    color: var(--highlight-dark);\n    cursor: pointer;\n}\n\n    button:hover,\n    button:focus,\n    a:hover,\n    a:focus {\n        color: var(--highlight-light);\n        text-decoration: none;\n    }\n\n.toc .nav > li.active > a {\n    color: var(--highlight-dark);\n}\n\n    .toc .nav > li.active > a:hover,\n    .toc .nav > li.active > a:focus {\n        color: var(--highlight-light);\n    }\n\n/*.pagination > .active > a {\n  background-color: var(--header-bg-color);\n  border-color: var(--header-bg-color);\n}\n\n.pagination > .active > a,\n.pagination > .active > a:focus,\n.pagination > .active > a:hover,\n.pagination > .active > span,\n.pagination > .active > span:focus,\n.pagination > .active > span:hover {\n  background-color: var(--highlight-light);\n  border-color: var(--highlight-light);\n}\n*/\n/* HEADINGS */\n\nh1 {\n    font-weight: 300;\n    font-size: 34px;\n    color: #000000b0;\n}\n\nh2 {\n    font-weight: 500;\n    font-size: 22px;\n    line-height: 1.8;\n}\n\nh3 {\n    font-weight: 400;\n    font-size: 18px;\n    line-height: 1.8;\n}\n\nh4 {\n    font-weight: 500;\n}\n\nh5 {\n    font-size: 14px;\n    font-weight: 500;\n    padding: 10px 0px;\n}\n\n.h6, h6 {\n    font-size: 13px;\n}\n\narticle h1 {\n    margin-top: 45px;\n    margin-bottom: 20px;\n}\n\narticle > h1:first-child {\n    margin-top: 10px;\n}\n\narticle h2,\narticle h3,\narticle h4 {\n    margin-top: 25px;\n    margin-bottom: 10px;\n}\n\narticle h2 {\n    margin-top: 35px;\n}\n\narticle h3 {\n    margin-top: 30px;\n}\n\narticle h4 {\n    padding-bottom: 6px;\n    border-bottom: 1px solid #ddd;\n    font-weight: 500;\n    font-size: 17px;\n}\n\nth {\n    font-weight: 500;\n}\n\nh1 + h2, h2 + h3, h3 + h4 {\n    margin-top: 0;\n}\n\narticle ul {\n    margin-bottom: 12px;\n}\n\narticle li {\n    margin-bottom: 4px;\n}\n\n#fields, #properties, #methods, #events {\n    font-weight: 500;\n    margin-top: 2em;\n}\n\n\n\n/* SIDEBAR */\n\n.toc .nav > li > a {\n    color: var(--toc-font-color);\n}\n\n.sidefilter {\n    background-color: #fff;\n    border-left: none;\n    border-right: none;\n}\n\n.sidefilter {\n    background-color: #fff;\n    border-left: none;\n    border-right: none;\n}\n\n.toc-filter {\n    padding: 5px;\n    margin: 0;\n    box-shadow: var(--card-box-shadow);\n    transition: var(--transition);\n    opacity: 0.5;\n}\n\n    .toc-filter:hover, .toc-filter:focus, .toc-filter:focus-within {\n        opacity: 1;\n    }\n\n    .toc-filter > input {\n        border: none;\n        background-color: inherit;\n        transition: inherit;\n    }\n\n    .toc-filter > .filter-icon {\n        display: none;\n    }\n\n.sidetoc > .toc {\n    background-color: #fff;\n    overflow-x: unset;\n}\n\n.sidetoc {\n    background-color: #fff;\n    border: none;\n}\n\n.toc {\n    margin: 0;\n    padding: 0;\n    font-size: 14px;\n}\n\n    .toc .nav > li {\n        position: relative;\n        display: block;\n        margin-bottom: 8px;\n        text-transform: capitalize;\n    }\n\n    .toc ul {\n        margin-top: 8px;\n        margin-left: 10px;\n        font-size: 14px;\n    }\n\n    .toc:first-child > ul {\n        margin-top: 0;\n    }\n\n        .toc:first-child > ul:first-child > li {\n            margin-top: 0;\n        }\n\n.sidetoc {\n    overflow-x: auto;\n    overflow-wrap: normal;\n    width: 260px;\n}\n\n.toc .level1 > li {\n    font-weight: 400;\n    margin-top: 8px;\n    position: relative;\n    font-size: 14px;\n}\n\n.toc .level2 {\n    font-weight: normal;\n    font-size: 14px;\n}\n\n.toc UL.level2 {\n    margin: 8px 0 0 15px;\n    font-size: 14px;\n}\n\n.expand-stub {\n    left: -10px;\n    font-family: \"WebComponentsIcons\";\n}\n\n.toc .nav > li.active > .expand-stub::before,\n.toc .nav > li.in > .expand-stub::before,\n.toc .nav > li.in.active > .expand-stub::before,\n.toc .nav > li.filtered > .expand-stub::before {\n    content: \"\\e015\";\n}\n\n.toc .nav > li > .expand-stub::before,\n.toc .nav > li.active > .expand-stub::before {\n    content: \"\\e014\";\n}\n\n\n/* ALERTS */\n\n.alert {\n    padding: 0px 0px 5px 0px;\n    margin-top: 20px;\n    color: inherit;\n    background-color: inherit;\n    border: none;\n    box-shadow: var(--card-box-shadow);\n}\n\n    .alert > p {\n        margin-bottom: 0;\n        padding: 5px 10px;\n    }\n\n    .alert > ul {\n        margin-bottom: 0;\n        padding: 5px 40px;\n    }\n\n    .alert > h5 {\n        padding: 10px 15px;\n        margin-top: 0;\n        text-transform: uppercase;\n        font-weight: 500;\n        border-radius: 4px 4px 0 0;\n    }\n\n.alert-info > h5 {\n    color: #1976d2;\n    border-bottom: 4px solid #1976d2;\n    background-color: #e3f2fd;\n}\n\n.alert-warning > h5 {\n    color: #f57f17;\n    border-bottom: 4px solid #f57f17;\n    background-color: #fff3e0;\n}\n\n.alert-danger > h5 {\n    color: #d32f2f;\n    border-bottom: 4px solid #d32f2f;\n    background-color: #ffebee;\n}\n\n/* CODE HIGHLIGHT */\npre {\n    padding: 9.5px;\n    margin: 20px 0;\n    font-size: 15px;\n    word-break: break-all;\n    word-wrap: break-word;\n    background-color: #f8f8f7;\n    border-radius: 4px;\n    border: none;\n    box-shadow: var(--card-box-shadow);\n}\n\n/* STYLE FOR IMAGES */\n\n.article .small-image {\n    margin-top: 15px;\n    box-shadow: var(--card-box-shadow);\n    max-width: 350px;\n}\n\n.article .medium-image {\n    margin-top: 15px;\n    box-shadow: var(--card-box-shadow);\n    max-width: 550px;\n}\n\n.article .large-image {\n    margin-top: 15px;\n    box-shadow: var(--card-box-shadow);\n    max-width: 700px;\n}\n\n*, :after, :before {\n    box-sizing: border-box;\n}\n\nheader {\n    background-color: var(--header-bg-color);\n}\n\n.article {\n    margin-top: 200px;\n    margin-bottom: 115px;\n}\n\n.sidefilter {\n    top: 200px;\n    margin: 0;\n    padding: 0;\n    width: 260px;\n}\n\n.toc-filter {\n    border-radius: 5px;\n    background: unset;\n    color: unset;\n    padding: 0;\n    position: relative;\n    margin: 0;\n}\n\n#toc_filter_input {\n    width: 100%;\n    height: 26px;\n    padding: 6px 12px;\n    font-size: 14px;\n    line-height: 1.42857143;\n    border: 1px solid #ccc;\n}\n\n\n.sidetoc {\n    top: 240px;\n}\n\n.navbar-brand {\n    height: unset;\n}\n\n.hidden-sm.col-md-2 {\n    padding-left: 0;\n}\n\n.sideaffix {\n    top: 150px;\n    font-size: 13px;\n    max-width: calc(12% - 5px);\n    margin-left: 5px;\n}\n\n.affix {\n    text-transform: capitalize;\n}\n\n    .affix ul > li > a {\n        text-transform: capitalize;\n    }\n\n    .affix ul > li > a {\n        padding-top: 3px;\n        padding-right: 12px;\n        padding-bottom: 3px;\n        padding-left: 14px;\n        text-overflow: ellipsis;\n        white-space: nowrap;\n        overflow: hidden;\n    }\n\n    .affix h5 {\n        font-weight: 500;\n    }\n\n    .affix ul ul > li > a:before {\n        top: unset;\n    }\n\n\n\n\n.article.grid-right {\n    margin-left: 280px;\n}\n\n@media only screen and (max-width: 768px) {\n    .article.grid-right {\n        margin-left: 0;\n    }\n}\n\n\n\n.sdkversion {\n    color: var(--highlight-dark);\n    font-weight: 500;\n}\n\n\n#search .form-control {\n    width: 100%;\n    height: 26px;\n    /* padding: 6px 12px; */\n    font-size: 14px;\n    line-height: 1.42857143;\n    border: 1px solid #ccc;\n}\n\n.container #breadcrumb {\n    float: left;\n}\n\n.breadcrumb li {\n    font-size: 14px;\n    text-transform: capitalize;\n}\n\n.opspan {\n    text-transform: uppercase;\n    padding: 3px 10px;\n    color: white;\n    font-weight: bold;\n    border-radius: 5px;\n}\n\n    .opspan.opspan-post {\n        background: #49cc90;\n    }\n\n    .opspan.opspan-put {\n        background: #fca130;\n    }\n\n    .opspan.opspan-delete {\n        background: #f93e3e;\n    }\n\n    .opspan.opspan-get {\n        background: #61affe;\n    }\n\n    .opspan.opspan-patch {\n        background: #50e3c2;\n    }\n\n    .opspan.opspan-head {\n        background: #9012fe;\n    }\n\n    .opspan.opspan-options {\n        background: #0d5aa7;\n    }\n\n.grad-bottom {\n    background: linear-gradient(rgb(0 0 0 / 0%), rgb(0 0 0 / 8%));\n    height: 5px;\n}\n\n.footer {\n    border-top: 1px solid #ededed;\n    background-color: #111;\n    padding: 15px 0;\n    color: #757575;\n}\n\n    .footer a.lnk {\n        color: #9e9e9e;\n    }\n\n.refdoc pre {\n    margin: 0;\n}\n\n.refdoc h4 {\n    margin-top: 40px;\n}\n\n.refdoc h4 {\n    margin-top: 50px;\n    padding-bottom: 3px;\n}\n\n.refdoc h5 {\n    padding-bottom: 3px;\n    margin-top: 16px;\n}\n\n.hljs-keyword {\n    color: rgb(86,156,214);\n}\n\n.hljs-string, .hljs-meta-string {\n    color: rgb(214, 157, 133);\n}\n\n.card.fw-horizontal {\n    text-align: left;\n    padding: 1.4rem;\n    flex-direction: row;\n    border-radius: 0.75rem;\n    box-shadow: 3px 3px 13px 0px rgb(255 255 255 / 42%);\n    /* height: 100%; */\n    align-items: flex-start;\n    gap: 1rem;\n    margin: 1rem 1rem;\n    max-height: 12rem;\n}\n\n@media (min-width: 768px) {\n    .card.fw-horizontal:first-child {\n        width: calc(66.66666667% + 2rem);\n    }\n}\n\n@media (min-width: 990px) {\n    .card.fw-horizontal:first-child {\n        margin: 1rem;\n        width: 25%;\n    }\n}\n\n.card {\n    padding: 1rem 2rem;\n    margin-bottom: 1rem;\n}\n\n.card {\n    position: relative;\n    display: -webkit-box;\n    display: -ms-flexbox;\n    display: flex;\n    flex-direction: column;\n    min-width: 0;\n    word-wrap: break-word;\n    /* background-color: var(--fw-card-bg); */\n    /* background-clip: border-box; */\n    border: 1px solid var(--fw-card-border-color);\n    border-radius: 0.5rem;\n    background: linear-gradient(12deg, #e3e3e3, white);\n    align-items: center;\n    margin: 1rem;\n    box-shadow: 3px 3px 10px 0px rgb(99 113 119 / 17%);\n}\n\n    .card .category-icon {\n        height: 4.5rem;\n        margin: 0 0.2em 0.6rem 0;\n    }\n\n    .card.fw-horizontal .fw-category-icon {\n        width: 4.5rem;\n        margin: 0.2rem 0 0 0;\n    }\n\n.card-body {\n    color: var(--fw-card-fg);\n}\n\n.card.fw-horizontal .card-title {\n    margin-bottom: 0.3rem;\n    padding-bottom: 0;\n}\n\n.cardRow {\n    display: flex;\n    flex-direction: row;\n    flex-wrap: wrap;\n    justify-content: center;\n    align-content: inherit;\n    align-items: stretch;\n    /* gap: 2rem; */\n    margin-bottom: 70px;\n}\n\n.card.fw-horizontal .card-body {\n    width: 75%;\n    overflow: hidden;\n    max-height: 100%;\n}\n\n.card-text {\n    color: var(--font-color);\n    font-size: 15px;\n    overflow: hidden;\n}\n\nH4.card-title {\n    margin-top: 0;\n    line-height: 1.3;\n    border: none;\n}\n\nH2.card-title {\n    margin-top: 0;\n    line-height: 1.2;\n    margin-bottom: 0.4rem;\n}\n\n.landingBackground {\n    background-image: url(../images/books_background.jpg);\n    position: absolute;\n    top: -50px;\n    left: 0;\n    right: 0;\n    height: 350px;\n    background-position: center center;\n    -webkit-background-size: cover;\n    background-size: cover;\n    z-index: -1;\n}\n\n\n    .landingBackground.searchResults {\n        height: 220px;\n    }\n\n.landing-search {\n    margin-top: 180px;\n    margin-bottom: 20px;\n}\n\n@media only screen and (max-width: 990px) {\n    .landingBackground {\n        top: 0px;\n        height: 410px;\n    }\n\n        .landingBackground.searchResults {\n            height: 180px;\n        }\n\n    .landing-search {\n        margin-top: 140px;\n    }\n}\n\n@media only screen and (max-width: 950px) {\n    .landing-search {\n        margin-top: 120px;\n        margin-bottom: 0;\n    }\n\n    .landingBackground {\n        top: -30px;\n        height: 420px;\n    }\n}\n\n@media only screen and (max-width: 900px) {\n    .landing-search {\n        margin-top: 80px;\n        margin-bottom: 0;\n    }\n\n    .landingBackground {\n        height: 440px;\n    }\n}\n\n\n@media only screen and (max-width: 768px) {\n    .landing-search {\n        margin-top: 20px;\n        margin-bottom: 40px;\n    }\n\n    .landingBackground.searchResults {\n        height: 250px;\n    }\n\n    .landingBackground {\n        height: 250px;\n    }\n}\n\n.search-form {\n    margin: auto;\n    width: 32rem;\n    display: flex !important;\n    flex-direction: column;\n    align-items: center;\n}\n\n#search.search-form .form-control {\n    width: unset;\n    font-size: 24px;\n    height: 42px;\n    width: 36rem;\n}\n\n.search-heading h2 {\n    color: white;\n    font-size: 29px;\n    white-space: nowrap;\n    font-weight: 300;\n    margin-bottom: 0.1rem;\n}\n\n.landingPage H1 {\n    text-align: center;\n}\n\n.landingPage #search-results {\n    margin-top: 60px;\n}\n\n.card.fw-horizontal .card-text {\n    -webkit-line-clamp: 2;\n    line-clamp: 2;\n    display: -webkit-inline-box;\n    -webkit-box-orient: vertical;\n}\n\n.landingPage ARTICLE H1:first-child {\n    display: none;\n}\n\nbody {\n    padding: 20px !important;\n}\n\n    body > div:first-child > hr + p {\n        display: none;\n    }\n\n    body > div:first-child hr {\n        display: none;\n    }\n\n    body > div:first-child {\n        margin-top: 20px;\n    }\n"
  },
  {
    "path": "global.json",
    "content": "{\n    \"sdk\": {\n        \"version\": \"10.0.100\",\n        \"rollForward\": \"feature\",\n        \"allowPrerelease\": false\n    }\n}\n"
  },
  {
    "path": "nuke/.editorconfig",
    "content": "[*.cs]\ndotnet_style_qualification_for_field = false:warning\ndotnet_style_qualification_for_property = false:warning\ndotnet_style_qualification_for_method = false:warning\ndotnet_style_qualification_for_event = false:warning\ndotnet_style_require_accessibility_modifiers = never:warning\n\ncsharp_style_expression_bodied_methods = true:silent\ncsharp_style_expression_bodied_properties = true:warning\ncsharp_style_expression_bodied_indexers = true:warning\ncsharp_style_expression_bodied_accessors = true:warning\n"
  },
  {
    "path": "nuke/Build.cs",
    "content": "using Microsoft.Build.Exceptions;\nusing Nuke.Common;\nusing Nuke.Common.CI.GitHubActions;\nusing Nuke.Common.IO;\nusing Nuke.Common.ProjectModel;\nusing Nuke.Common.Tooling;\nusing Nuke.Common.Tools.DotNet;\nusing Nuke.Common.Tools.GitHub;\nusing Nuke.Common.Tools.NuGet;\nusing Nuke.Common.Utilities.Collections;\nusing Octokit;\nusing Octokit.Internal;\nusing Serilog;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\n\nusing static Nuke.Common.IO.PathConstruction;\nusing static Nuke.Common.Tools.DotNet.DotNetTasks;\n// ReSharper disable ArrangeThisQualifier\n\nclass Build : NukeBuild\n{\n    /// Support plugins are available for:\n    ///   - JetBrains ReSharper        https://nuke.build/resharper\n    ///   - JetBrains Rider            https://nuke.build/rider\n    ///   - Microsoft VisualStudio     https://nuke.build/visualstudio\n    ///   - Microsoft VSCode           https://nuke.build/vscode\n\n    public static int Main() => Execute<Build>(x => x.RunUnitTests);\n\n    [Nuke.Common.Parameter(\"Configuration to build - Default is 'Debug' (local) or 'Release' (server)\")]\n    readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;\n\n    [Nuke.Common.Parameter(\"ReleaseNotesFilePath - To determine the lates changelog version\")]\n    readonly AbsolutePath ReleaseNotesFilePath = RootDirectory / \"Changelog.md\";\n\n    [Nuke.Common.Parameter(\"common.props file path - to determine the configured version\")]\n    readonly AbsolutePath CommonPropsFilePath = RootDirectory / \"src\" / \"common.props\";\n\n    [Solution]\n    readonly Solution Solution;\n\n    AbsolutePath SourceDirectory => RootDirectory / \"src\";\n\n    AbsolutePath ResultDirectory => RootDirectory / \"artifacts\";\n\n    GitHubActions GitHubActions => GitHubActions.Instance;\n\n    IReadOnlyList<ReleaseNotes> ChangeLog { get; set; }\n\n    ReleaseNotes LatestReleaseNotes { get; set; }\n\n    SemVersion SemVersion { get; set; }\n\n    string Version { get; set; }\n\n    string VersionPostFix { get; set; }\n\n    protected override void OnBuildInitialized()\n    {\n        var parser = new ReleaseNotesParser();\n\n        Log.Debug(\"Reading ChangeLog {FilePath}...\", ReleaseNotesFilePath);\n        ChangeLog = parser.Parse(File.ReadAllText(ReleaseNotesFilePath));\n        ChangeLog.NotNull(\"ChangeLog / ReleaseNotes could not be read!\");\n\n        LatestReleaseNotes = ChangeLog.First();\n        LatestReleaseNotes.NotNull(\"LatestVersion could not be read!\");\n\n        var propsParser = new CommonPropsParser();\n\n        var propsVersion = propsParser.Parse(CommonPropsFilePath);\n\n        propsVersion.NotNull(\"Version from common.props could not be read!\");\n\n        Assert.True(propsVersion == LatestReleaseNotes.Version,\n                $\"The version in common.props ({propsVersion}) does not \" +\n                $\"equal the latest version in the changelog ({LatestReleaseNotes.Version})\");\n\n        Log.Debug(\"Using version: {LatestVersion}\", propsVersion);\n        SemVersion = LatestReleaseNotes.SemVersion;\n        Version = propsVersion.ToString();\n\n        if (GitHubActions != null)\n        {\n            Log.Debug(\"Add Version Postfix if under CI - GithubAction(s)...\");\n\n            var buildNumber = GitHubActions.RunNumber;\n\n            if (ScheduledTargets.Contains(Default))\n            {\n                VersionPostFix = $\"-ci.{buildNumber}\";\n            }\n            else if (ScheduledTargets.Contains(PrePublish))\n            {\n                VersionPostFix = $\"-pre.{buildNumber}\";\n            }\n        }\n        else if (ScheduledTargets.Contains(PrePublish))\n        {\n            VersionPostFix = $\"-pre\";\n        }\n\n        Log.Information(\"Building version {Version} with postfix {VersionPostFix}\", Version, VersionPostFix);\n    }\n\n    Target Clean => _ => _\n        .Before(Restore)\n        .Executes(() =>\n        {\n            SourceDirectory.GlobDirectories(\"**/bin\", \"**/obj\").ForEach(dir => dir.DeleteDirectory());\n        });\n\n    Target Restore => _ => _\n        .Executes(() =>\n        {\n            DotNetRestore(s => s.SetProjectFile(Solution));\n        });\n\n    Target Compile => _ => _\n        .DependsOn(Restore)\n        .Executes(() =>\n        {\n            DotNetBuild(s => s\n                .SetProjectFile(Solution)\n                .SetConfiguration(Configuration)\n                .SetProperty(\"GeneratePackageOnBuild\", \"True\")\n                .SetProperty(\"VersionPostFix\", VersionPostFix ?? string.Empty));\n        });\n\n    Target RunUnitTests => _ => _\n        .DependsOn(Compile)\n        .Executes(() =>\n        {\n            var TestProject = SourceDirectory / \"ElectronNET.IntegrationTests\" / \"ElectronNET.IntegrationTests.csproj\";\n\n            DotNetTest(s => s\n                .SetProjectFile(TestProject)\n                .SetConfiguration(Configuration)\n                .When(_ => GitHubActions.Instance is not null, x => x.SetLoggers(\"GitHubActions\"))\n            );\n        });\n\n    Target PublishPackages => _ => _\n        .DependsOn(Compile)\n        .DependsOn(RunUnitTests)\n        .Executes(() =>\n        {\n            var apiKey = Environment.GetEnvironmentVariable(\"NUGET_API_KEY\");\n\n\n            if (apiKey.IsNullOrEmpty())\n            {\n                throw new BuildAbortedException(\"Could not resolve the NuGet API key.\");\n            }\n\n            foreach (var nupkg in ResultDirectory.GlobFiles(\"*.nupkg\"))\n            {\n                DotNetNuGetPush(s => s\n                    .SetTargetPath(nupkg)\n                    .SetSource(\"https://api.nuget.org/v3/index.json\")\n                    .SetApiKey(apiKey));\n            }\n        });\n\n    Target PublishPreRelease => _ => _\n        .DependsOn(PublishPackages)\n        .Executes(() =>\n        {\n            string gitHubToken;\n\n            if (GitHubActions != null)\n            {\n                gitHubToken = GitHubActions.Token;\n            }\n            else\n            {\n                gitHubToken = Environment.GetEnvironmentVariable(\"GITHUB_TOKEN\");\n            }\n\n            if (gitHubToken.IsNullOrEmpty())\n            {\n                throw new BuildAbortedException(\"Could not resolve GitHub token.\");\n            }\n\n            var credentials = new Credentials(gitHubToken);\n\n            GitHubTasks.GitHubClient = new GitHubClient(\n                new ProductHeaderValue(nameof(NukeBuild)),\n                new InMemoryCredentialStore(credentials));\n\n            GitHubTasks.GitHubClient.Repository.Release\n                .Create(\"ElectronNET\", \"Electron.NET\", new NewRelease(Version + VersionPostFix)\n                {\n                    Name = \"ElectronNET.Core \" + Version + VersionPostFix,\n                    Body = String.Join(Environment.NewLine, LatestReleaseNotes.Notes),\n                    Prerelease = true,\n                    TargetCommitish = \"develop\",\n                });\n        });\n\n    Target PublishRelease => _ => _\n        .DependsOn(PublishPackages)\n        .Executes(() =>\n        {\n            string gitHubToken;\n\n            if (GitHubActions != null)\n            {\n                gitHubToken = GitHubActions.Token;\n            }\n            else\n            {\n                gitHubToken = Environment.GetEnvironmentVariable(\"GITHUB_TOKEN\");\n            }\n\n            if (gitHubToken.IsNullOrEmpty())\n            {\n                throw new BuildAbortedException(\"Could not resolve GitHub token.\");\n            }\n\n            var credentials = new Credentials(gitHubToken);\n\n            GitHubTasks.GitHubClient = new GitHubClient(\n                new ProductHeaderValue(nameof(NukeBuild)),\n                new InMemoryCredentialStore(credentials));\n\n            GitHubTasks.GitHubClient.Repository.Release\n                .Create(\"ElectronNET\", \"Electron.NET\", new NewRelease(Version)\n                {\n                    Name = \"ElectronNET.Core \" + Version,\n                    Body = String.Join(Environment.NewLine, LatestReleaseNotes.Notes),\n                    Prerelease = false,\n                    TargetCommitish = \"main\",\n                });\n        });\n\n    Target Package => _ => _\n        .DependsOn(RunUnitTests)\n        .DependsOn(Compile);\n\n    Target Default => _ => _\n        .DependsOn(Package);\n\n    Target Publish => _ => _\n        .DependsOn(PublishRelease);\n\n    Target PrePublish => _ => _\n        .DependsOn(PublishPreRelease);\n}\n"
  },
  {
    "path": "nuke/CommonPropsParser.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Xml.Linq;\n\n/// <summary>\n/// Parses a version from an MSBuild .props file (XML).\n/// </summary>\npublic sealed class CommonPropsParser\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ReleaseNotesParser\"/> class.\n    /// </summary>\n    public CommonPropsParser()\n    {\n    }\n\n    public Version Parse(string propsPath)\n    {\n        var doc = XDocument.Load(propsPath);\n\n        var versionElement = doc\n            .Descendants()\n            .FirstOrDefault(e => e.Name.LocalName == \"Version\");\n\n        if (Version.TryParse(versionElement?.Value.Trim(), out var version))\n        {\n            version = new Version(version.Major, version.Minor, version.Build);\n            return version;\n        }\n\n        return null;\n    }\n}"
  },
  {
    "path": "nuke/Configuration.cs",
    "content": "using System;\nusing System.ComponentModel;\nusing System.Linq;\nusing Nuke.Common.Tooling;\n\n[TypeConverter(typeof(TypeConverter<Configuration>))]\npublic class Configuration : Enumeration\n{\n    public static Configuration Debug = new Configuration { Value = nameof(Debug) };\n    public static Configuration Release = new Configuration { Value = nameof(Release) };\n\n    public static implicit operator string(Configuration configuration)\n    {\n        return configuration.Value;\n    }\n}\n"
  },
  {
    "path": "nuke/Directory.Build.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <!-- This file prevents unintended imports of unrelated MSBuild files -->\n  <!-- Uncomment to include parent Directory.Build.props file -->\n  <!--<Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />-->\n\n</Project>\n"
  },
  {
    "path": "nuke/Directory.Build.targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <!-- This file prevents unintended imports of unrelated MSBuild files -->\n  <!-- Uncomment to include parent Directory.Build.targets file -->\n  <!--<Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.targets', '$(MSBuildThisFileDirectory)../'))\" />-->\n\n</Project>\n"
  },
  {
    "path": "nuke/Extensions/StringExtensions.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE file in the project root for more information.\n\nusing System;\n\n// ReSharper disable once CheckNamespace\n/// <summary>\n/// Contains extension methods for <see cref=\"System.String\"/>.\n/// </summary>\n/// <remarks>\n/// Original from Cake build tool source:\n/// https://github.com/cake-build/cake/blob/9828d7b246d332054896e52ba56983822feb3f05/src/Cake.Core/Extensions/StringExtensions.cs\n/// </remarks>\npublic static class StringExtensions\n{\n    /// <summary>\n    /// Quotes the specified <see cref=\"System.String\"/>.\n    /// </summary>\n    /// <param name=\"value\">The string to quote.</param>\n    /// <returns>A quoted string.</returns>\n    public static string Quote(this string value)\n    {\n        if (!IsQuoted(value))\n        {\n            value = string.Concat(\"\\\"\", value, \"\\\"\");\n        }\n\n        return value;\n    }\n\n    /// <summary>\n    /// Unquote the specified <see cref=\"System.String\"/>.\n    /// </summary>\n    /// <param name=\"value\">The string to unquote.</param>\n    /// <returns>An unquoted string.</returns>\n    public static string UnQuote(this string value)\n    {\n        if (IsQuoted(value))\n        {\n            value = value.Trim('\"');\n        }\n\n        return value;\n    }\n\n    /// <summary>\n    /// Splits the <see cref=\"String\"/> into lines.\n    /// </summary>\n    /// <param name=\"content\">The string to split.</param>\n    /// <returns>The lines making up the provided string.</returns>\n    public static string[] SplitLines(this string content)\n    {\n        content = NormalizeLineEndings(content);\n        return content.Split(new[] { \"\\r\\n\" }, StringSplitOptions.None);\n    }\n\n    /// <summary>\n    /// Normalizes the line endings in a <see cref=\"String\"/>.\n    /// </summary>\n    /// <param name=\"value\">The string to normalize line endings in.</param>\n    /// <returns>A <see cref=\"String\"/> with normalized line endings.</returns>\n    public static string NormalizeLineEndings(this string value)\n    {\n        if (value != null)\n        {\n            value = value.Replace(\"\\r\\n\", \"\\n\");\n            value = value.Replace(\"\\r\", string.Empty);\n            return value.Replace(\"\\n\", \"\\r\\n\");\n        }\n\n        return string.Empty;\n    }\n\n    private static bool IsQuoted(this string value)\n    {\n        return value.StartsWith(\"\\\"\", StringComparison.OrdinalIgnoreCase)\n               && value.EndsWith(\"\\\"\", StringComparison.OrdinalIgnoreCase);\n    }\n}"
  },
  {
    "path": "nuke/ReleaseNotes.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE file in the project root for more information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\n/// <summary>\n/// Represent release notes.\n/// </summary>\n/// <remarks>\n/// Original from Cake build tool source:\n/// https://github.com/cake-build/cake/blob/9828d7b246d332054896e52ba56983822feb3f05/src/Cake.Common/ReleaseNotes.cs\n/// </remarks>\npublic sealed class ReleaseNotes\n{\n    private readonly List<string> _notes;\n\n    /// <summary>\n    /// Gets the version.\n    /// </summary>\n    /// <value>The version.</value>\n    public SemVersion SemVersion { get; }\n\n    /// <summary>\n    /// Gets the version.\n    /// </summary>\n    /// <value>The version.</value>\n    public Version Version { get; }\n\n    /// <summary>\n    /// Gets the release notes.\n    /// </summary>\n    /// <value>The release notes.</value>\n    public IReadOnlyList<string> Notes => _notes;\n\n    /// <summary>\n    /// Gets the raw text of the line that <see cref=\"Version\"/> was extracted from.\n    /// </summary>\n    /// <value>The raw text of the Version line.</value>\n    public string RawVersionLine { get; }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ReleaseNotes\"/> class.\n    /// </summary>\n    /// <param name=\"semVersion\">The semantic version.</param>\n    /// <param name=\"notes\">The notes.</param>\n    /// <param name=\"rawVersionLine\">The raw text of the version line.</param>\n    public ReleaseNotes(SemVersion semVersion, IEnumerable<string> notes, string rawVersionLine)\n        : this(\n            semVersion?.AssemblyVersion ?? throw new ArgumentNullException(nameof(semVersion)),\n            semVersion,\n            notes,\n            rawVersionLine)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ReleaseNotes\"/> class.\n    /// </summary>\n    /// <param name=\"version\">The version.</param>\n    /// <param name=\"notes\">The notes.</param>\n    /// <param name=\"rawVersionLine\">The raw text of the version line.</param>\n    public ReleaseNotes(Version version, IEnumerable<string> notes, string rawVersionLine)\n        : this(\n            version ?? throw new ArgumentNullException(nameof(version)),\n            new SemVersion(version.Major, version.Minor, version.Build),\n            notes,\n            rawVersionLine)\n    {\n    }\n\n    private ReleaseNotes(Version version, SemVersion semVersion, IEnumerable<string> notes, string rawVersionLine)\n    {\n        Version = version ?? throw new ArgumentNullException(nameof(version));\n        SemVersion = semVersion ?? throw new ArgumentNullException(nameof(semVersion));\n        RawVersionLine = rawVersionLine;\n        _notes = new List<string>(notes ?? Enumerable.Empty<string>());\n    }\n}"
  },
  {
    "path": "nuke/ReleaseNotesParser.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE file in the project root for more information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing Microsoft.Build.Exceptions;\n\n/// <summary>\n/// The release notes parser.\n/// </summary>\n/// <remarks>\n/// Original from Cake build tool source:\n/// https://github.com/cake-build/cake/blob/9828d7b246d332054896e52ba56983822feb3f05/src/Cake.Common/ReleaseNotesParser.cs\n/// </remarks>\npublic sealed class ReleaseNotesParser\n{\n    private readonly Regex _versionRegex;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ReleaseNotesParser\"/> class.\n    /// </summary>\n    public ReleaseNotesParser()\n    {\n        _versionRegex = new Regex(@\"(?<Version>\\d+(\\s*\\.\\s*\\d+){0,3})(?<Release>-[a-z][0-9a-z-]*)?\");\n    }\n\n    /// <summary>\n    /// Parses all release notes.\n    /// </summary>\n    /// <param name=\"content\">The content.</param>\n    /// <returns>All release notes.</returns>\n    public IReadOnlyList<ReleaseNotes> Parse(string content)\n    {\n        if (content == null)\n        {\n            throw new ArgumentNullException(nameof(content));\n        }\n\n        var lines = content.SplitLines();\n        if (lines.Length > 0)\n        {\n            var line = lines[0].Trim();\n\n            if (line.StartsWith(\"#\", StringComparison.OrdinalIgnoreCase))\n            {\n                return ParseComplexFormat(lines);\n            }\n\n            if (line.StartsWith(\"*\", StringComparison.OrdinalIgnoreCase))\n            {\n                return ParseSimpleFormat(lines);\n            }\n        }\n\n        throw new BuildAbortedException(\"Unknown release notes format.\");\n    }\n\n    private IReadOnlyList<ReleaseNotes> ParseComplexFormat(string[] lines)\n    {\n        var lineIndex = 0;\n        var result = new List<ReleaseNotes>();\n\n        while (true)\n        {\n            if (lineIndex >= lines.Length)\n            {\n                break;\n            }\n\n            // Create release notes.\n            var semVer = SemVersion.Zero;\n            var version = SemVersion.TryParse(lines[lineIndex], out semVer);\n            if (!version)\n            {\n                throw new BuildAbortedException(\"Could not parse version from release notes header.\");\n            }\n\n            var rawVersionLine = lines[lineIndex];\n\n            // Increase the line index.\n            lineIndex++;\n\n            // Parse content.\n            var notes = new List<string>();\n\n            while (true)\n            {\n                // Sanity checks.\n                if (lineIndex >= lines.Length)\n                {\n                    break;\n                }\n\n                if (lines[lineIndex].StartsWith(\"# \", StringComparison.OrdinalIgnoreCase))\n                {\n                    break;\n                }\n\n                // Get the current line.\n                var line = (lines[lineIndex] ?? string.Empty).Trim();\n\n                if (!string.IsNullOrWhiteSpace(line))\n                {\n                    notes.Add(line);\n                }\n\n                lineIndex++;\n            }\n\n            result.Add(new ReleaseNotes(semVer, notes, rawVersionLine));\n        }\n\n        return result.OrderByDescending(x => x.SemVersion).ToArray();\n    }\n\n    private IReadOnlyList<ReleaseNotes> ParseSimpleFormat(string[] lines)\n    {\n        var lineIndex = 0;\n        var result = new List<ReleaseNotes>();\n\n        while (true)\n        {\n            if (lineIndex >= lines.Length)\n            {\n                break;\n            }\n\n            // Trim the current line.\n            var line = (lines[lineIndex] ?? string.Empty);\n\n            if (string.IsNullOrWhiteSpace(line))\n            {\n                lineIndex++;\n                continue;\n            }\n\n            // Parse header.\n            var semVer = SemVersion.Zero;\n            var version = SemVersion.TryParse(lines[lineIndex], out semVer);\n\n            if (!version)\n            {\n                throw new BuildAbortedException(\"Could not parse version from release notes header.\");\n            }\n\n            // Parse the description.\n            line = line.Substring(semVer.ToString().Length).Trim('-', ' ');\n\n            // Add the release notes to the result.\n            result.Add(new ReleaseNotes(semVer, new[] { line }, line));\n\n            lineIndex++;\n        }\n\n        return result.OrderByDescending(x => x.SemVersion).ToArray();\n    }\n}"
  },
  {
    "path": "nuke/SemVersion.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n// See the LICENSE file in the project root for more information.\n\nusing System;\nusing System.Globalization;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\n/// <summary>\n/// Class for representing semantic versions.\n/// </summary>\n/// <remarks>\n/// Original from Cake build tool source:\n/// https://github.com/cake-build/cake/blob/9828d7b246d332054896e52ba56983822feb3f05/src/Cake.Common/SemanticVersion.cs\n/// </remarks>\npublic class SemVersion : IComparable, IComparable<SemVersion>, IEquatable<SemVersion>\n{\n    /// <summary>\n    /// Gets the default version of a SemanticVersion.\n    /// </summary>\n    public static SemVersion Zero { get; } = new SemVersion(0, 0, 0, null, null, \"0.0.0\");\n\n    /// <summary>\n    /// Regex property for parsing a semantic version number.\n    /// </summary>\n    public static readonly Regex SemVerRegex =\n        new Regex(\n            @\"(?<Major>0|(?:[1-9]\\d*))(?:\\.(?<Minor>0|(?:[1-9]\\d*))(?:\\.(?<Patch>0|(?:[1-9]\\d*)))?(?:\\-(?<PreRelease>[0-9A-Z\\.-]+))?(?:\\+(?<Meta>[0-9A-Z\\.-]+))?)?\",\n            RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);\n\n    /// <summary>\n    /// Gets the major number of the version.\n    /// </summary>\n    public int Major { get; }\n\n    /// <summary>\n    /// Gets the minor number of the version.\n    /// </summary>\n    public int Minor { get; }\n\n    /// <summary>\n    /// Gets the patch number of the version.\n    /// </summary>\n    public int Patch { get; }\n\n    /// <summary>\n    /// Gets the prerelease of the version.\n    /// </summary>\n    public string PreRelease { get; }\n\n    /// <summary>\n    /// Gets the meta of the version.\n    /// </summary>\n    public string Meta { get; }\n\n    /// <summary>\n    /// Gets a value indicating whether semantic version is a prerelease or not.\n    /// </summary>\n    public bool IsPreRelease { get; }\n\n    /// <summary>\n    /// Gets a value indicating whether semantic version has meta or not.\n    /// </summary>\n    public bool HasMeta { get; }\n\n    /// <summary>\n    /// Gets the VersionString of the semantic version.\n    /// </summary>\n    public string VersionString { get; }\n\n    /// <summary>\n    /// Gets the AssemblyVersion of the semantic version.\n    /// </summary>\n    public Version AssemblyVersion { get; }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"SemVersion\"/> class.\n    /// </summary>\n    /// <param name=\"major\">Major number.</param>\n    /// <param name=\"minor\">Minor number.</param>\n    /// <param name=\"patch\">Patch number.</param>\n    /// <param name=\"preRelease\">Prerelease string.</param>\n    /// <param name=\"meta\">Meta string.</param>\n    public SemVersion(int major, int minor, int patch, string preRelease = null, string meta = null) : this(major,\n        minor, patch, preRelease, meta, null)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"SemVersion\"/> class.\n    /// </summary>\n    /// <param name=\"major\">Major number.</param>\n    /// <param name=\"minor\">Minor number.</param>\n    /// <param name=\"patch\">Patch number.</param>\n    /// <param name=\"preRelease\">Prerelease string.</param>\n    /// <param name=\"meta\">Meta string.</param>\n    /// <param name=\"versionString\">The complete version number.</param>\n    public SemVersion(int major, int minor, int patch, string preRelease, string meta, string versionString)\n    {\n        Major = major;\n        Minor = minor;\n        Patch = patch;\n        AssemblyVersion = new Version(major, minor, patch);\n        IsPreRelease = !string.IsNullOrEmpty(preRelease);\n        HasMeta = !string.IsNullOrEmpty(meta);\n        PreRelease = IsPreRelease ? preRelease : null;\n        Meta = HasMeta ? meta : null;\n\n        if (!string.IsNullOrEmpty(versionString))\n        {\n            VersionString = versionString;\n        }\n        else\n        {\n            var sb = new StringBuilder();\n            sb.AppendFormat(CultureInfo.InvariantCulture, \"{0}.{1}.{2}\", Major, Minor, Patch);\n\n            if (IsPreRelease)\n            {\n                sb.AppendFormat(CultureInfo.InvariantCulture, \"-{0}\", PreRelease);\n            }\n\n            if (HasMeta)\n            {\n                sb.AppendFormat(CultureInfo.InvariantCulture, \"+{0}\", Meta);\n            }\n\n            VersionString = sb.ToString();\n        }\n    }\n\n    /// <summary>\n    /// Method which tries to parse a semantic version string.\n    /// </summary>\n    /// <param name=\"version\">the version that should be parsed.</param>\n    /// <param name=\"semVersion\">the out parameter the parsed version should be stored in.</param>\n    /// <returns>Returns a boolean indicating if the parse was successful.</returns>\n    public static bool TryParse(string version,\n        out SemVersion semVersion)\n    {\n        semVersion = Zero;\n\n        if (string.IsNullOrEmpty(version))\n        {\n            return false;\n        }\n\n        var match = SemVerRegex.Match(version);\n        if (!match.Success)\n        {\n            return false;\n        }\n\n        if (!int.TryParse(\n                match.Groups[\"Major\"].Value,\n                NumberStyles.Integer,\n                CultureInfo.InvariantCulture,\n                out var major) ||\n            !int.TryParse(\n                match.Groups[\"Minor\"].Value,\n                NumberStyles.Integer,\n                CultureInfo.InvariantCulture,\n                out var minor) ||\n            !int.TryParse(\n                match.Groups[\"Patch\"].Value,\n                NumberStyles.Integer,\n                CultureInfo.InvariantCulture,\n                out var patch))\n        {\n            return false;\n        }\n\n        semVersion = new SemVersion(\n            major,\n            minor,\n            patch,\n            match.Groups[\"PreRelease\"]?.Value,\n            match.Groups[\"Meta\"]?.Value,\n            version);\n\n        return true;\n    }\n\n    /// <summary>\n    /// Checks if two SemVersion objects are equal.\n    /// </summary>\n    /// <param name=\"other\">the other SemVersion want to test equality to.</param>\n    /// <returns>A boolean indicating whether the objecst we're equal or not.</returns>\n    public bool Equals(SemVersion other)\n    {\n        return other is object\n               && Major == other.Major\n               && Minor == other.Minor\n               && Patch == other.Patch\n               && string.Equals(PreRelease, other.PreRelease, StringComparison.OrdinalIgnoreCase)\n               && string.Equals(Meta, other.Meta, StringComparison.OrdinalIgnoreCase);\n    }\n\n    /// <summary>\n    /// Compares to SemVersion objects to and another.\n    /// </summary>\n    /// <param name=\"other\">The SemVersion object we compare with.</param>\n    /// <returns>Return 0 if the objects are identical, 1 if the version is newer and -1 if the version is older.</returns>\n    public int CompareTo(SemVersion other)\n    {\n        if (other is null)\n        {\n            return 1;\n        }\n\n        if (Equals(other))\n        {\n            return 0;\n        }\n\n        if (Major > other.Major)\n        {\n            return 1;\n        }\n\n        if (Major < other.Major)\n        {\n            return -1;\n        }\n\n        if (Minor > other.Minor)\n        {\n            return 1;\n        }\n\n        if (Minor < other.Minor)\n        {\n            return -1;\n        }\n\n        if (Patch > other.Patch)\n        {\n            return 1;\n        }\n\n        if (Patch < other.Patch)\n        {\n            return -1;\n        }\n\n        if (IsPreRelease != other.IsPreRelease)\n        {\n            return other.IsPreRelease ? 1 : -1;\n        }\n\n        switch (StringComparer.InvariantCultureIgnoreCase.Compare(PreRelease, other.PreRelease))\n        {\n            case 1:\n                return 1;\n\n            case -1:\n                return -1;\n\n            default:\n            {\n                return (string.IsNullOrEmpty(Meta) != string.IsNullOrEmpty(other.Meta))\n                    ? string.IsNullOrEmpty(Meta) ? 1 : -1\n                    : StringComparer.InvariantCultureIgnoreCase.Compare(Meta, other.Meta);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Compares to SemVersion objects to and another.\n    /// </summary>\n    /// <param name=\"obj\">The object we compare with.</param>\n    /// <returns>Return 0 if the objects are identical, 1 if the version is newer and -1 if the version is older.</returns>\n    public int CompareTo(object obj)\n    {\n        return (obj is SemVersion semVersion)\n            ? CompareTo(semVersion)\n            : -1;\n    }\n\n    /// <summary>\n    /// Equals-method for the SemVersion class.\n    /// </summary>\n    /// <param name=\"obj\">the other SemVersion want to test equality to.</param>\n    /// <returns>A boolean indicating whether the objecst we're equal or not.</returns>\n    public override bool Equals(object obj)\n    {\n        return (obj is SemVersion semVersion)\n               && Equals(semVersion);\n    }\n\n    /// <summary>\n    /// Method for getting the hashcode of the SemVersion object.\n    /// </summary>\n    /// <returns>The hashcode of the SemVersion object.</returns>\n    public override int GetHashCode()\n    {\n        unchecked\n        {\n            var hashCode = Major;\n            hashCode = (hashCode * 397) ^ Minor;\n            hashCode = (hashCode * 397) ^ Patch;\n            hashCode = (hashCode * 397) ^\n                       (PreRelease != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(PreRelease) : 0);\n            hashCode = (hashCode * 397) ^ (Meta != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(Meta) : 0);\n            return hashCode;\n        }\n    }\n\n    /// <summary>\n    /// Returns the string representation of an SemVersion object.\n    /// </summary>\n    /// <returns>The string representation of the object.</returns>\n    public override string ToString()\n    {\n        int[] verParts = { Major, Minor, Patch };\n        string ver = string.Join(\".\", verParts);\n        return $\"{ver}{(IsPreRelease ? \"-\" : string.Empty)}{PreRelease}{Meta}\";\n    }\n\n    /// <summary>\n    /// The greater than-operator for the SemVersion class.\n    /// </summary>\n    /// <param name=\"operand1\">first SemVersion.</param>\n    /// <param name=\"operand2\">second. SemVersion.</param>\n    /// <returns>A value indicating if the operand1 was greater than operand2.</returns>\n    public static bool operator >(SemVersion operand1, SemVersion operand2)\n        => operand1 is { } && operand1.CompareTo(operand2) == 1;\n\n    /// <summary>\n    /// The less than-operator for the SemVersion class.\n    /// </summary>\n    /// <param name=\"operand1\">first SemVersion.</param>\n    /// <param name=\"operand2\">second. SemVersion.</param>\n    /// <returns>A value indicating if the operand1 was less than operand2.</returns>\n    public static bool operator <(SemVersion operand1, SemVersion operand2)\n        => operand1 is { }\n            ? operand1.CompareTo(operand2) == -1\n            : operand2 is { };\n\n    /// <summary>\n    /// The greater than or equal to-operator for the SemVersion class.\n    /// </summary>\n    /// <param name=\"operand1\">first SemVersion.</param>\n    /// <param name=\"operand2\">second. SemVersion.</param>\n    /// <returns>A value indicating if the operand1 was greater than or equal to operand2.</returns>\n    public static bool operator >=(SemVersion operand1, SemVersion operand2)\n        => operand1 is { }\n            ? operand1.CompareTo(operand2) >= 0\n            : operand2 is null;\n\n    /// <summary>\n    /// The lesser than or equal to-operator for the SemVersion class.\n    /// </summary>\n    /// <param name=\"operand1\">first SemVersion.</param>\n    /// <param name=\"operand2\">second. SemVersion.</param>\n    /// <returns>A value indicating if the operand1 was lesser than or equal to operand2.</returns>\n    public static bool operator <=(SemVersion operand1, SemVersion operand2)\n        => operand1 is null || operand1.CompareTo(operand2) <= 0;\n\n    /// <summary>\n    /// The equal to-operator for the SemVersion class.\n    /// </summary>\n    /// <param name=\"operand1\">first SemVersion.</param>\n    /// <param name=\"operand2\">second. SemVersion.</param>\n    /// <returns>A value indicating if the operand1 was equal to operand2.</returns>\n    public static bool operator ==(SemVersion operand1, SemVersion operand2)\n        => operand1?.Equals(operand2) ?? operand2 is null;\n\n    /// <summary>\n    /// The not equal to-operator for the SemVersion class.\n    /// </summary>\n    /// <param name=\"operand1\">first SemVersion.</param>\n    /// <param name=\"operand2\">second. SemVersion.</param>\n    /// <returns>A value indicating if the operand1 was not equal to operand2.</returns>\n    public static bool operator !=(SemVersion operand1, SemVersion operand2)\n        => !(operand1?.Equals(operand2) ?? operand2 is null);\n}"
  },
  {
    "path": "nuke/_build.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</TargetFramework>\n    <RootNamespace></RootNamespace>\n    <NoWarn>CS0649;CS0169</NoWarn>\n    <NukeRootDirectory>..</NukeRootDirectory>\n    <NukeScriptDirectory>..</NukeScriptDirectory>\n    <NukeTelemetryVersion>1</NukeTelemetryVersion>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Build\" Version=\"18.0.2\" />\n    <PackageReference Include=\"Microsoft.Build.Tasks.Core\" Version=\"18.0.2\" />\n    <PackageReference Include=\"Nuke.Common\" Version=\"10.1.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageDownload Include=\"NuGet.CommandLine\" Version=\"[6.12.2]\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/.editorconfig",
    "content": "﻿[*.cs]\n\n# CA1416: Validate platform compatibility\ndotnet_diagnostic.CA1416.severity = error\n"
  },
  {
    "path": "src/ElectronNET/.electron/.gitkeep",
    "content": ""
  },
  {
    "path": "src/ElectronNET/ElectronNET.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"..\\common.props\" />\n\n  <PropertyGroup>\n    <TargetFrameworks>net6.0;net8.0;net10.0</TargetFrameworks>\n    <PackageOutputPath>..\\..\\artifacts</PackageOutputPath>\n    <PackageId>$(PackageNamePrefix)</PackageId>\n    <Title>$(PackageId)</Title>\n    <Description>$(DescriptionFirstPart) This package contains the ElectronNET project system.</Description>\n    <GenerateDocumentationFile>false</GenerateDocumentationFile>\n    <IncludeSymbols>false</IncludeSymbols>\n    <Nullable>disable</Nullable>\n  </PropertyGroup>\n  <ItemGroup>\n    <None Include=\"PackageIcon.png\" Pack=\"true\" PackagePath=\"\\\" />\n    <None Include=\"../../README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Folder Include=\".electron\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\ElectronNET.Host\\**\\*.js;..\\ElectronNET.Host\\**\\*.html\" Exclude=\"..\\ElectronNET.Host\\node_modules\\**\">\n      <Link>.electron\\%(RecursiveDir)%(FileName)%(Extension)</Link>\n      <CopyToOutputDirectory>Never</CopyToOutputDirectory>\n      <Pack>true</Pack>\n      <PackagePath>.electron\\</PackagePath>\n   </None>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"build\\**\\*\">\n      <Pack>true</Pack>\n      <PackagePath>build\\</PackagePath>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ElectronNET.API\\ElectronNET.API.csproj\">\n      <ReferenceOutputAssembly>True</ReferenceOutputAssembly>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <None Update=\"build\\ElectronNETRules.Project2.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n    </None>\n    <None Update=\"build\\ElectronNETRules.Project.xaml\">\n      <Generator>MSBuild:Compile</Generator>\n    </None>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/ElectronNET/build/ElectronNET.Core.props",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Label=\"ElectronNetCommon\">\n    <ElectronVersion>30.4.0</ElectronVersion>\n    <ElectronBuilderVersion>26.0</ElectronBuilderVersion>\n    <RuntimeIdentifier Condition=\"'$(RuntimeIdentifier)' == ''\">win-x64</RuntimeIdentifier>\n    <ElectronSingleInstance>true</ElectronSingleInstance>\n    <ElectronSplashScreen></ElectronSplashScreen>\n    <ElectronIcon></ElectronIcon>\n    <PackageIcon></PackageIcon>\n    <ElectronPackageId>$(MSBuildProjectName.Replace(\".\", \"-\").ToLower())</ElectronPackageId>\n    <ElectronBuilderJson>electron-builder.json</ElectronBuilderJson>\n    <Title>$(MSBuildProjectName)</Title>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>\n    <ImportNuGetBuildTasksPackTargetsFromSdk>false</ImportNuGetBuildTasksPackTargetsFromSdk>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <CustomAfterDirectoryBuildTargets>$(MSBuildThisFileDirectory)ElectronNET.LateImport.targets</CustomAfterDirectoryBuildTargets>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <CollectUpToDateCheckBuiltDesignTimeDependsOn>$(CollectUpToDateCheckBuiltDesignTimeDependsOn);ElectronCollectUpToDateCheckBuiltDesignTime</CollectUpToDateCheckBuiltDesignTimeDependsOn>\n    <FileSystemPublishDependsOn>$(FileSystemPublishDependsOn);ElectronFileSystemPublishClearItems</FileSystemPublishDependsOn>\n  </PropertyGroup>\n\n</Project>"
  },
  {
    "path": "src/ElectronNET/build/ElectronNET.Core.targets",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup Condition=\"'$(ElectronExecutable)' == ''\">\n    <WinPrefix>win</WinPrefix>\n    <ElectronExecutable Condition=\"'$(RuntimeIdentifier.StartsWith($(WinPrefix)))' == 'true'\">$(Title)</ElectronExecutable>\n    <ElectronExecutable Condition=\"'$(RuntimeIdentifier.StartsWith($(WinPrefix)))' != 'true'\">$(ElectronPackageId)</ElectronExecutable>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <_IsMsAspNetProject>False</_IsMsAspNetProject>\n    <_IsMsAspNetProject Condition=\"'$(UsingMicrosoftNETSdkWeb)' == 'true'\">True</_IsMsAspNetProject>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <PackageId Condition=\"'$(PackageId)' == ''\">$(ElectronPackageId)</PackageId>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AssemblyMetadata Include=\"ElectronExecutable\" Value=\"$(ElectronExecutable)\" />\n    <AssemblyMetadata Include=\"ElectronVersion\" Value=\"$(ElectronVersion)\" />\n    <AssemblyMetadata Include=\"RuntimeIdentifier\" Value=\"$(RuntimeIdentifier)\" />\n    <AssemblyMetadata Include=\"ElectronSingleInstance\" Value=\"$(ElectronSingleInstance)\" />\n    <AssemblyMetadata Include=\"Title\" Value=\"$(Title)\" />\n    <AssemblyMetadata Include=\"Version\" Value=\"$(Version)\" />\n    <AssemblyMetadata Include=\"BuildConfiguration\" Value=\"$(Configuration)\" />\n    <AssemblyMetadata Include=\"IsAspNet\" Value=\"$(_IsMsAspNetProject)\" />\n  </ItemGroup>\n\n  <!-- Import migration validation checks -->\n  <Import Project=\"$(MSBuildThisFileDirectory)ElectronNET.MigrationChecks.targets\" />\n\n</Project>"
  },
  {
    "path": "src/ElectronNET/build/ElectronNET.DesignTime.targets",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <ElectronEnablePropertyPage Condition=\"'$(ElectronEnablePropertyPage)' == '' and '$(VisualStudioVersion)' &gt;= '17.0'\">True</ElectronEnablePropertyPage>\n  </PropertyGroup>\n\n  <!-- This adds the custom Electron.NET tab to the project designer -->\n  <ItemGroup>\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)ElectronNETRules.Project.xaml\" Condition=\"'$(ElectronEnablePropertyPage)' == 'True'\">\n      <Context>Project</Context>\n    </PropertyPageSchema>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PropertyPageSchema Include=\"$(MSBuildThisFileDirectory)ElectronNETRules.Project2.xaml\" Condition=\"'$(ElectronEnablePropertyPage)' == 'True'\">\n      <Context>Project</Context>\n    </PropertyPageSchema>\n  </ItemGroup>\n\n  <!-- Remove all 'Pack' menu items -->\n  <ItemGroup>\n    <ProjectCapability Remove=\"Pack\" />\n  </ItemGroup>\n\n  <!-- Remove the nuget package creation tab from the project designer -->\n  <ItemGroup>\n    <PropertyPageSchema Remove=\"$(ManagedXamlResourcesDirectory)DebugPropertyPage.xaml\" />\n    <PropertyPageSchema Remove=\"$(ManagedXamlResourcesDirectory)ResourcesPropertyPage.xaml\" />\n    <PropertyPageSchema Remove=\"$(ManagedXamlResourcesDirectory)PackagePropertyPage.xaml\" />\n    <PropertyPageSchema Remove=\"$(XamlResourcesDirectory)IISDebugPropertyPage.xaml\" />\n    <PropertyPageSchema Remove=\"$(XamlResourcesDirectory)IISExpressDebugPropertyPage.xaml\" />\n  </ItemGroup>\n\n  <Target Name=\"ElectronRemoveAppDesignerTabs\" BeforeTargets=\"UpdateAspNetToFrameworkReference\" >\n\n    <ItemGroup>\n      <PropertyPageSchema Remove=\"$(ManagedXamlResourcesDirectory)DebugPropertyPage.xaml\" />\n      <PropertyPageSchema Remove=\"$(ManagedXamlResourcesDirectory)ResourcesPropertyPage.xaml\" />\n      <PropertyPageSchema Remove=\"$(ManagedXamlResourcesDirectory)PackagePropertyPage.xaml\" />\n      <PropertyPageSchema Remove=\"$(XamlResourcesDirectory)IISDebugPropertyPage.xaml\" />\n      <PropertyPageSchema Remove=\"$(XamlResourcesDirectory)IISExpressDebugPropertyPage.xaml\" />\n    </ItemGroup>\n\n  </Target>\n\n  <!-- This is also run at design time, each time when a property of the project is changed -->\n\n  <Target Name=\"ElectronMakePathRelative1\" BeforeTargets=\"UpdateAspNetToFrameworkReference\" Condition=\"\n      '$(DesignTimeBuild)'=='true'\n      and '$(ElectronSplashScreen)' != ''\n      and '$([System.IO.Path]::IsPathRooted($(ElectronSplashScreen)))' == 'true'\n      and '$(ElectronSplashScreen.StartsWith($(MSBuildProjectDirectory)))' == 'true'\n    \">\n\n    <Message Text=\"ElectronMakePathRelative start: ElectronSplashScreen: $(ElectronSplashScreen)\" Importance=\"High\" />\n    <Message Text=\"ElectronMakePathRelative IsPathRooted: $([System.IO.Path]::IsPathRooted($(ElectronSplashScreen)))\" Importance=\"High\" />\n    <Message Text=\"ElectronMakePathRelative StartsWith: $(ElectronSplashScreen.StartsWith('$(MSBuildProjectDirectory)'))\" Importance=\"High\" />\n\n    <PropertyGroup>\n      <ElectronRelativeplashScreen>$(ElectronSplashScreen.Replace('$(MSBuildProjectDirectory)', '').TrimStart('\\'))</ElectronRelativeplashScreen>\n    </PropertyGroup>\n\n    <Message Text=\"ElectronMakePathRelative ElectronRelativeplashScreen: $(ElectronRelativeplashScreen)\" Importance=\"High\" />\n    <XmlPoke XmlInputPath=\"$(MSBuildProjectFullPath)\"\n             Query=\"/Project/PropertyGroup[@Label='ElectronNetCommon']/ElectronSplashScreen\"\n             Value=\"$(ElectronRelativeplashScreen)\" />\n  </Target>\n\n  <Target Name=\"ElectronMakePathRelative2\" BeforeTargets=\"UpdateAspNetToFrameworkReference\" Condition=\"\n      '$(DesignTimeBuild)'=='true'\n      and '$(ElectronIcon)' != ''\n      and '$([System.IO.Path]::IsPathRooted($(ElectronIcon)))' == 'true'\n      and '$(ElectronIcon.StartsWith($(MSBuildProjectDirectory)))' == 'true'\n    \">\n\n    <Message Text=\"ElectronMakePathRelative start: ElectronIcon: $(ElectronIcon)\" Importance=\"High\" />\n    <Message Text=\"ElectronMakePathRelative IsPathRooted: $([System.IO.Path]::IsPathRooted($(ElectronIcon)))\" Importance=\"High\" />\n    <Message Text=\"ElectronMakePathRelative StartsWith: $(ElectronIcon.StartsWith('$(MSBuildProjectDirectory)'))\" Importance=\"High\" />\n\n    <PropertyGroup>\n      <ElectronRelativeElectronIcon>$(ElectronIcon.Replace('$(MSBuildProjectDirectory)', '').TrimStart('\\'))</ElectronRelativeElectronIcon>\n    </PropertyGroup>\n\n    <Message Text=\"ElectronMakePathRelative ElectronRelativeElectronIcon: $(ElectronRelativeElectronIcon)\" Importance=\"High\" />\n    <XmlPoke XmlInputPath=\"$(MSBuildProjectFullPath)\"\n             Query=\"/Project/PropertyGroup[@Label='ElectronNetCommon']/ElectronIcon\"\n             Value=\"$(ElectronRelativeElectronIcon)\" />\n  </Target>\n\n  <!-- This target runs during design-time builds -->\n  <Target Name=\"FixElectronSplashScreen\" Condition=\"\n      '$(DesignTimeBuild)'!='true'\n      and '$(ElectronSplashScreen)' != ''\n      and $([System.IO.Path]::IsPathRooted($(ElectronSplashScreen))) == 'true'\n      and $([System.String]::StartsWith($(ElectronSplashScreen), '$(MSBuildProjectDirectory)')) == 'true'\n    \" DependsOnTargets=\"ResolveProjectReferences\">\n\n    <!-- Compute the relative path by removing the project folder prefix -->\n    <PropertyGroup>\n      <!-- Ensure the project directory ends with a backslash -->\n      <_ProjectDir>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)'))\\</_ProjectDir>\n      <RelativeElectronSplashScreen>\n        $([System.String]::Substring($(ElectronSplashScreen), \n        $([System.String]::Length($(_ProjectDir)))))\n      </RelativeElectronSplashScreen>\n    </PropertyGroup>\n\n    <Message Text=\"ElectronSplashScreen is absolute. Updating to relative path: $(RelativeElectronSplashScreen)\"\n             Importance=\"High\" />\n\n    <!-- Update the project file using XmlPoke -->\n    <XmlPoke XmlInputPath=\"$(MSBuildProjectFullPath)\"\n             Query=\"/Project/PropertyGroup[@Label='ElectronNetCommon']/ElectronSplashScreen/text()\"\n             Value=\"$(RelativeElectronSplashScreen)\" />\n    <Message Text=\"Project file updated with relative ElectronSplashScreen.\" Importance=\"High\" />\n  </Target>\n\n  <!-- Collects items for the up-to-date check in VS -->\n  <Target Name=\"ElectronCollectUpToDateCheckBuiltDesignTime\" DependsOnTargets=\"ElectronResolvePaths\">\n\n    <ItemGroup>\n      <UpToDateCheckBuilt Include=\"@(ElectronIntermediatePackageJson->'$(OutDir)%(TargetPath)')\" Original=\"@(ElectronIntermediatePackageJson)\" />\n      <UpToDateCheckBuilt Include=\"@(ElectronCustomHookPackageJson->'$(OutDir)%(TargetPath)')\" Original=\"@(ElectronCustomHookPackageJson)\" />\n    </ItemGroup>\n\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "src/ElectronNET/build/ElectronNET.LateImport.targets",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n <!--<Import Project=\"$(MSBuildThisFileDirectory)ElectronNET.Tasks.targets\"  />-->\n  <UsingTask TaskName=\"ElectronNET.Build.ReplaceTemplateTask\"\n             AssemblyFile=\"$(MSBuildThisFileDirectory)ElectronNET.Build.dll\" />\n\n  <UsingTask TaskName=\"ElectronNET.Build.DumpItemMetadataTask\"\n             AssemblyFile=\"$(MSBuildThisFileDirectory)ElectronNET.Build.dll\" />\n\n  <UsingTask TaskName=\"ElectronNET.Build.RemoveEnvironmentVariables\"\n             AssemblyFile=\"$(MSBuildThisFileDirectory)ElectronNET.Build.dll\" />\n\n  <!-- Adjust the properties of items in the ElectronHostHook folder (if present) -->\n\n  <ItemGroup>\n    <Content Update=\"ElectronHostHook\\package.json\">\n      <CopyToOutputDirectory>Never</CopyToOutputDirectory>\n      <CopyToPublishDirectory>Never</CopyToPublishDirectory>\n    </Content>\n    <Content Update=\"ElectronHostHook\\package-lock.json\">\n      <CopyToOutputDirectory>Never</CopyToOutputDirectory>\n      <CopyToPublishDirectory>Never</CopyToPublishDirectory>\n    </Content>\n    <Content Update=\"ElectronHostHook\\tsconfig.json\">\n      <CopyToOutputDirectory>Never</CopyToOutputDirectory>\n      <CopyToPublishDirectory>Never</CopyToPublishDirectory>\n    </Content>\n  </ItemGroup>\n  <ItemGroup>\n    <None Remove=\"ElectronHostHook\\*.ts\" />\n  </ItemGroup>\n  <ItemGroup>\n    <TypeScriptCompile Include=\"ElectronHostHook\\*.ts\" />\n  </ItemGroup>\n\n  <!-- Static Evaluation -->\n  <ItemGroup>\n    <ElectronCustomHookTsFiles Include=\"ElectronHostHook\\*.ts\" />\n  </ItemGroup>\n\n  <!-- Create variables for our output paths -->\n  <PropertyGroup>\n    <ElectronSourceFilesPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)\\..\\..\\ElectronNET.Host'))</ElectronSourceFilesPath>\n    <ElectronSourceFilesPath Condition=\"!Exists($(ElectronSourceFilesPath))\">$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)\\..\\.electron'))</ElectronSourceFilesPath>\n    <ElectronDirName>.electron</ElectronDirName>\n    <ElectronSplashScreenFileName Condition=\"'$(ElectronSplashScreen)' != ''\">$([System.IO.Path]::GetFileName($(ElectronSplashScreen)))</ElectronSplashScreenFileName>\n    <ElectronIconFileName Condition=\"'$(ElectronIcon)' != ''\">$([System.IO.Path]::GetFileName($(ElectronIcon)))</ElectronIconFileName>\n  </PropertyGroup>\n\n\n  <!-- Targets -->\n\n  <Target Name=\"ElectronBeforeClean\" AfterTargets=\"BeforeClean\" DependsOnTargets=\"ElectronResolvePaths\">\n    <ItemGroup>\n      <Clean Include=\"$(ElectronOutDir)**\" />\n    </ItemGroup>\n\n    <!--<Message Text=\"ElectronBeforeClean - Clean Files: @(Clean)\" Importance=\"High\" />-->\n  </Target>\n\n  <Target Name=\"ElectronClean\" AfterTargets=\"CoreClean\" DependsOnTargets=\"ElectronResolvePaths\">\n\n    <RemoveDir Directories=\"$(ElectronOutDir)\" />\n\n  </Target>\n\n  <Target Name=\"ElectronSetPaths\">\n\n    <PropertyGroup>\n      <ElectronOutDir>$(OutDir)$(ElectronDirName)\\</ElectronOutDir>\n      <ElectronTargetDir>$(TargetDir)$(ElectronDirName)\\</ElectronTargetDir>\n      <ElectronIntermediateOutputPath>$(IntermediateOutputPath)$(ElectronDirName)\\</ElectronIntermediateOutputPath>\n      <ElectronIntermediatePackageJson>$(ElectronIntermediateOutputPath)package.json</ElectronIntermediatePackageJson>\n    </PropertyGroup>\n\n  </Target>\n\n <Target Name=\"EnsureElectronBuilderJson\" DependsOnTargets=\"ResolveProjectReferences\" >\n\n   <PropertyGroup>\n     <_ProjectPropertiesFolder>$(MSBuildProjectDirectory)\\Properties\\</_ProjectPropertiesFolder>\n     <_ElectronBuilderExpectedPath>$(_ProjectPropertiesFolder)$(ElectronBuilderJson)</_ElectronBuilderExpectedPath>\n     <_NeedCopyElectronBuilderFile>True</_NeedCopyElectronBuilderFile>\n     <_NeedCopyElectronBuilderFile Condition=\"Exists($(_ElectronBuilderExpectedPath))\">False</_NeedCopyElectronBuilderFile>\n   </PropertyGroup>\n\n   <Message Text=\"EnsureElectronBuilderJson: $(_ProjectPropertiesFolder)\" Importance=\"High\" />\n   <Message Text=\"EnsureElectronBuilderJson: $(_ElectronBuilderExpectedPath)\" Importance=\"High\" />\n   <Message Text=\"EnsureElectronBuilderJson: $(_NeedCopyElectronBuilderFile)\" Importance=\"High\" />\n\n   <Copy Condition=\"'$(_NeedCopyElectronBuilderFile)' == 'True'\" SourceFiles=\"$(MSBuildThisFileDirectory)electron-builder.json\" DestinationFiles=\"$(_ProjectPropertiesFolder)$(ElectronBuilderJson)\" />\n\n </Target>\n\n\n  <!-- This is also run at design time, each time when a property of the project is changed -->\n  <Target Name=\"ElectronCreatePackageJson\" DependsOnTargets=\"ResolveProjectReferences;ElectronSetPaths\">\n\n    <Message Text=\"Creating package.json from template...\" Importance=\"High\" />\n    <Message Text=\"OutDir: $(OutDir)\" Importance=\"High\" />\n\n    <!-- This makes sure the directories get created in PrepareForBuild -->\n    <ItemGroup>\n      <CreateDirectory Include=\"$(ElectronIntermediateOutputPath)\" />\n      <CreateDirectory Include=\"$(ElectronOutDir)\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n      <ElectronSingleInstance Condition=\"'$(ElectronSingleInstance)' == ''\">true</ElectronSingleInstance>\n    </PropertyGroup>\n\n    <PropertyGroup>\n      <ElectronTargetName Condition=\"'$(ElectronTargetName)' == ''\">$(TargetName)</ElectronTargetName>\n    </PropertyGroup>\n\n    <PropertyGroup>\n      <!-- Version may have only 3 parts -->\n      <Version>$([System.Text.RegularExpressions.Regex]::Replace('$(Version)', '^(\\d+\\.\\d+\\.\\d+)(?:\\.\\d+)?(.*)$', '$1$2'))</Version>\n      <!-- Electron Builder uses title for the installation dir on Linux, but it should not have spaces -->\n      <LinuxPrefix>linux</LinuxPrefix>\n      <ElectronTitle>$(Title)</ElectronTitle>\n      <ElectronTitle  Condition=\"'$(RuntimeIdentifier.StartsWith($(LinuxPrefix)))' == 'true'\">$(Title.Replace(' ', '-'))</ElectronTitle>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <TemplateProperty Include=\"ElectronPackageId\" Value=\"$(ElectronPackageId)\" />\n      <TemplateProperty Include=\"Title\" Value=\"$(Title)\" />\n      <TemplateProperty Include=\"ElectronTitle\" Value=\"$(ElectronTitle)\" />\n      <TemplateProperty Include=\"Version\" Value=\"$(Version)\" />\n      <TemplateProperty Include=\"Description\" Value=\"$(Description)\" />\n      <TemplateProperty Include=\"ProjectUrl\" Value=\"$(ProjectUrl)\" />\n      <TemplateProperty Include=\"License\" Value=\"$(License)\" />\n      <TemplateProperty Include=\"Company\" Value=\"$(Company)\" />\n      <TemplateProperty Include=\"ElectronSplashScreen\" Value=\"$(ElectronSplashScreenFileName)\" />\n      <TemplateProperty Include=\"ElectronVersion\" Value=\"$(ElectronVersion)\" />\n      <TemplateProperty Include=\"TargetName\" Value=\"$(ElectronTargetName)\" />\n      <TemplateProperty Include=\"ElectronSingleInstance\" Value=\"$(ElectronSingleInstance.ToLower())\" />\n    </ItemGroup>\n\n    <MakeDir Directories=\"$(ElectronIntermediateOutputPath)\" />\n\n    <ReplaceTemplateTask TemplateFile=\"$(MSBuildThisFileDirectory)package.template.json\"\n                         OutputFile=\"$(ElectronIntermediatePackageJson)\"\n                         TemplateProperties=\"@(TemplateProperty)\" />\n  </Target>\n\n\n  <Target Name=\"ElectronSetIntermediatePublishDir\"\n          BeforeTargets=\"AssignTargetPaths\"\n          DependsOnTargets=\"ElectronResolvePaths\">\n\n    <PropertyGroup Condition=\"'$(UsingMicrosoftNETSdkWeb)' != 'true'\">\n      <_NonIntermediatePublishDir>$(PublishDir)</_NonIntermediatePublishDir>\n      <PublishUrl>$(PublishDir)</PublishUrl>\n      <PublishDir>$(IntermediateOutputPath)PubTmp\\</PublishDir>\n    </PropertyGroup>\n\n    <RemoveDir Directories=\"$(PublishDir);$(PublishUrl)\" Condition=\"'$(UsingMicrosoftNETSdkWeb)' != 'true'\" />\n    <MakeDir Directories=\"$(PublishDir);$(PublishUrl)\" Condition=\"'$(UsingMicrosoftNETSdkWeb)' != 'true'\" />\n\n  </Target>\n\n\n  <Target Name=\"ElectronResolvePaths\"\n          BeforeTargets=\"AssignTargetPaths\"\n          DependsOnTargets=\"ResolveProjectReferences;ElectronCreatePackageJson;EnsureElectronBuilderJson;ElectronSetPaths\">\n\n    <ItemGroup>\n      <ElectronCustomHookPackageJson Include=\"ElectronHostHook\\package.json\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n      <ElectronHasCustomHookCode>false</ElectronHasCustomHookCode>\n      <ElectronHasCustomHookCode Condition=\"'@(ElectronCustomHookTsFiles->Count())' &gt; 1 AND '@(ElectronCustomHookPackageJson->Count())' == 1\">true</ElectronHasCustomHookCode>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <ElectronSourceFiles\n        Include=\"$(ElectronSourceFilesPath)\\**\\*.js;$(ElectronSourceFilesPath)\\**\\*.json;$(ElectronSourceFilesPath)\\**\\*.html\"\n        Exclude=\"$(ElectronSourceFilesPath)\\**\\build-helper.js\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <ElectronSourceFiles Remove=\"$(ElectronSourceFilesPath)\\ElectronHostHook\\**\" Condition=\"'$(ElectronHasCustomHookCode)' == 'true'\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <ElectronSourceFiles Update=\"@(ElectronSourceFiles)\">\n        <Link>$(ElectronDirName)\\%(RecursiveDir)%(FileName)%(Extension)</Link>\n        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      </ElectronSourceFiles>\n    </ItemGroup>\n\n    <AssignTargetPath Files=\"@(ElectronSourceFiles)\" RootFolder=\"$(MSBuildProjectDirectory)\">\n      <Output TaskParameter=\"AssignedFiles\" ItemName=\"ElectronSourceFilesWithTargetPath\" />\n    </AssignTargetPath>\n\n    <ItemGroup>\n      <FilesForPackagingFromProject Include=\"@(ElectronSourceFilesWithTargetPath->'%(Identity)')\"/>\n      <ContentWithTargetPath Include=\"@(ElectronSourceFilesWithTargetPath->'%(Identity)')\"/>\n      <Content Include=\"@(ElectronSourceFiles->'%(Identity)')\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <ElectronCustomHookPackageJson Remove=\"@(ElectronCustomHookPackageJson)\" Condition=\"'$(ElectronHasCustomHookCode)' != 'true'\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <ElectronCustomHookPackageJson Update=\"@(ElectronCustomHookPackageJson)\" Condition=\"'$(ElectronHasCustomHookCode)' == 'true'\" >\n        <TargetPath>$(ElectronDirName)\\%(RelativeDir)%(FileName)%(Extension)</TargetPath>\n      </ElectronCustomHookPackageJson>\n    </ItemGroup>\n\n    <ItemGroup>\n      <ElectronIntermediatePackageJson Include=\"$(ElectronIntermediatePackageJson)\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <ElectronIntermediatePackageJson Update=\"@(ElectronIntermediatePackageJson)\" >\n        <TargetPath>$(ElectronDirName)\\%(FileName)%(Extension)</TargetPath>\n      </ElectronIntermediatePackageJson>\n    </ItemGroup>\n\n    <ItemGroup>\n      <ElectronPackageJsonFiles Include=\"@(ElectronCustomHookPackageJson)\" />\n      <ElectronPackageJsonFiles Include=\"@(ElectronIntermediatePackageJson)\" />\n    </ItemGroup>\n\n  </Target>\n\n\n  <!-- Run before GetTypeScriptOutputForPublishing to adjust the target directory -->\n  <Target Name=\"ElectronAdjustHostHookOutput\" BeforeTargets=\"GetTypeScriptOutputForPublishing\" DependsOnTargets=\"CompileTypeScriptWithTSConfig\">\n\n    <ItemGroup>\n      <GeneratedJavascript Update=\"@(GeneratedJavascript)\">\n        <DestinationRelativePath>$(ElectronDirName)\\%(DestinationRelativePath)</DestinationRelativePath>\n        <TargetPath>$(ElectronDirName)\\%(DestinationRelativePath)</TargetPath>\n        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      </GeneratedJavascript>\n    </ItemGroup>\n  </Target>\n\n\n  <Target Name=\"ElectronGetCopyToOutputDirectoryItems\" BeforeTargets=\"GetCopyToOutputDirectoryItems\">\n\n    <ItemGroup>\n      <!--<_ElectronFiles Include=\"$(ElectronIntermediatePackageJson)\" />-->\n      <_ElectronFiles Include=\"$(ElectronSplashScreen)\"  Condition=\"'$(ElectronSplashScreen)'!=''\" />\n      <_ElectronFiles Include=\"$(ElectronIcon)\"  Condition=\"'$(ElectronIcon)'!=''\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <_ElectronFiles Update=\"**\">\n        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      </_ElectronFiles>\n    </ItemGroup>\n\n    <Message Importance=\"High\" Text=\"_ElectronFiles: @(_ElectronFiles)\" />\n\n    <ItemGroup>\n      <_ElectronFilesToCopy Include=\"@(_ElectronFiles->'%(FullPath)')\" />\n    </ItemGroup>\n\n    <Message Importance=\"High\" Text=\"_ElectronFilesToCopy: @(_ElectronFilesToCopy)\" />\n\n    <ItemGroup>\n      <_ElectronFilesToCopyWithTargetPath Include=\"@(_ElectronFilesToCopy)\">\n        <TargetPath>$(ElectronDirName)\\%(FileName)%(Extension)</TargetPath>\n      </_ElectronFilesToCopyWithTargetPath>\n    </ItemGroup>\n\n    <Message Text=\"_ElectronFilesToCopyWithTargetPath: @(_ElectronFilesToCopyWithTargetPath)\" />\n    <Message Text=\"_ElectronFilesToCopyWithTargetPath: @(_ElectronFilesToCopyWithTargetPath->'%(TargetPath)')\" />\n    <Message Text=\"_ElectronFilesToCopyWithTargetPath: @(_ElectronFilesToCopyWithTargetPath->'%(CopyToOutputDirectory)')\" />\n\n    <!-- The _SourceItems properties are internal to Microsoft.Common.targets,\n         but necessary to use here because there is no public equivalent -->\n    <ItemGroup>\n      <AllItemsFullPathWithTargetPath                 Include=\"@(_ElectronFilesToCopyWithTargetPath)\"/>\n      <_SourceItemsToCopyToOutputDirectoryIfDifferent Include=\"@(_ElectronFilesToCopyWithTargetPath)\"/>\n    </ItemGroup>\n\n  </Target>\n\n  <Target Name=\"ElectronResetHostHook\"\n          Inputs=\"@(ElectronCustomHookPackageJson)\"\n          Outputs=\"@(ElectronCustomHookPackageJson->'$(OutDir)%(TargetPath)')\"\n          AfterTargets=\"CopyFilesToOutputDirectory\"\n          >\n\n    <PropertyGroup>\n      <ElectronHookTargetModuleDir>$(OutDir)$(ElectronDirName)\\node_modules\\electron-host-hook</ElectronHookTargetModuleDir>\n    </PropertyGroup>\n\n    <RemoveDir Directories=\"$(ElectronHookTargetModuleDir)\" Condition=\"Exists($(ElectronHookTargetModuleDir))\" />\n  </Target>\n\n  <Target Name=\"ElectronCheckVersionMismatch\">\n\n    <PropertyGroup>\n      <ElectronArch Condition=\"'$(RuntimeIdentifier)' == 'win-x64'\">x64</ElectronArch>\n      <ElectronArch Condition=\"'$(RuntimeIdentifier)' == 'win-x86'\">ia32</ElectronArch>\n      <ElectronArch Condition=\"'$(RuntimeIdentifier)' == 'win-arm64'\">arm64</ElectronArch>\n      <ElectronArch Condition=\"'$(RuntimeIdentifier)' == 'linux-x64'\">x64</ElectronArch>\n      <ElectronArch Condition=\"'$(RuntimeIdentifier)' == 'linux-arm'\">armv7l</ElectronArch>\n      <ElectronArch Condition=\"'$(RuntimeIdentifier)' == 'linux-arm64'\">arm64</ElectronArch>\n      <ElectronArch Condition=\"'$(RuntimeIdentifier)' == 'osx-x64'\">x64</ElectronArch>\n      <ElectronArch Condition=\"'$(RuntimeIdentifier)' == 'osx-arm64'\">arm64</ElectronArch>\n\n      <ElectronPlatform Condition=\"'$(RuntimeIdentifier)' == 'win-x64' OR '$(RuntimeIdentifier)' == 'win-x86' OR '$(RuntimeIdentifier)' == 'win-arm64'\">win</ElectronPlatform>\n      <ElectronPlatform Condition=\"'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm' OR '$(RuntimeIdentifier)' == 'linux-arm64'\">linux</ElectronPlatform>\n      <ElectronPlatform Condition=\"'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64'\">mac</ElectronPlatform>\n     \n      <!-- npm uses different OS names than Electron -->\n      <NpmOs Condition=\"'$(ElectronPlatform)' == 'win'\">win32</NpmOs>\n      <NpmOs Condition=\"'$(ElectronPlatform)' == 'linux'\">linux</NpmOs>\n      <NpmOs Condition=\"'$(ElectronPlatform)' == 'mac'\">darwin</NpmOs>\n\n      <!-- npm CPU is same as ElectronArch except for linux-arm -->\n      <NpmCpu>$(ElectronArch)</NpmCpu>\n      <NpmCpu Condition=\"'$(RuntimeIdentifier)' == 'linux-arm'\">arm</NpmCpu>\n     \n      <_CurrentOSPlatform Condition=\"$([MSBuild]::IsOSPlatform('Windows'))\">win</_CurrentOSPlatform>\n      <_CurrentOSPlatform Condition=\"$([MSBuild]::IsOSPlatform('Linux'))\">linux</_CurrentOSPlatform>\n      <_CurrentOSPlatform Condition=\"$([MSBuild]::IsOSPlatform('OSX'))\">mac</_CurrentOSPlatform>\n    </PropertyGroup>\n\n    <!-- Validate that the target platform matches the current OS -->\n    <PropertyGroup>\n      <IsLinuxWsl>false</IsLinuxWsl>\n      <IsLinuxWsl Condition=\"'$(ElectronPlatform)' == 'linux' AND '$(_CurrentOSPlatform)' == 'win'\">true</IsLinuxWsl>\n\n      <_IsCrossCompileAllowed>false</_IsCrossCompileAllowed>\n      <!-- Allow Linux builds on Windows via WSL -->\n      <_IsCrossCompileAllowed Condition=\"'$(_CurrentOSPlatform)' == 'win' AND '$(ElectronPlatform)' == 'linux' AND '$(IsLinuxWsl)' == 'true'\">true</_IsCrossCompileAllowed>\n\n      <_IsPlatformMismatch>false</_IsPlatformMismatch>\n      <_IsPlatformMismatch Condition=\"'$(_CurrentOSPlatform)' != '$(ElectronPlatform)' AND '$(_IsCrossCompileAllowed)' != 'true'\">true</_IsPlatformMismatch>\n\n    </PropertyGroup>\n\n  </Target>\n\n\n  <Target Name=\"ElectronConfigureApp\"\n          Inputs=\"@(ElectronPackageJsonFiles)\"\n          Outputs=\"@(ElectronPackageJsonFiles->'$(OutDir)%(TargetPath)')\"\n          AfterTargets=\"CopyFilesToOutputDirectory\"\n          DependsOnTargets=\"ElectronResetHostHook;ElectronCheckVersionMismatch\"\n          >\n\n    <Copy SourceFiles=\"@(ElectronPackageJsonFiles)\" DestinationFiles=\"@(ElectronPackageJsonFiles->'$(OutDir)%(TargetPath)')\" >\n      <Output TaskParameter=\"CopiedFiles\" ItemName=\"_CopiedFiles\" />\n    </Copy>\n\n    <!--<Message Importance=\"High\" Text=\"ElectronDumpInfo: _CopiedFiles\" />\n    <DumpItemMetadataTask Items=\"@(_CopiedFiles)\" />-->\n\n    <Touch Files=\"@(_CopiedFiles)\" />\n\n    <PropertyGroup>\n      <ElectronOutputPath>$([System.IO.Path]::GetFullPath('$(ElectronOutDir)'))</ElectronOutputPath>\n      <_NpmCmd>npm install --no-bin-links</_NpmCmd>\n      <!-- Add cross-platform parameters when there's a platform mismatch (for remote debugging preparation) -->\n      <_NpmCmd Condition=\"'$(_IsPlatformMismatch)' == 'true'\">$(_NpmCmd) --os=$(NpmOs) --cpu=$(NpmCpu) --arch=$(NpmCpu) --platform=$(NpmOs)</_NpmCmd>\n      <_NpmCmd Condition=\"'$(IsLinuxWsl)' == 'true'\">wsl bash -ic '$(_NpmCmd)'</_NpmCmd>\n    </PropertyGroup>\n\n    <!--<Message Importance=\"High\" Text=\"ElectronConfigureApp: CopiedFiles - @(_CopiedFiles)\" />-->\n\n    <Message Importance=\"High\" Text=\"Running command: $(_NpmCmd) in folder:  $(ElectronOutputPath)\" Condition=\"@(_CopiedFiles->Count()) > 0\" />\n\n    <Exec Command=\"$(_NpmCmd)\" WorkingDirectory=\"$(ElectronOutputPath)\" Timeout=\"600000\" StandardOutputImportance=\"High\" StandardErrorImportance=\"High\" ContinueOnError=\"false\" Condition=\"@(_CopiedFiles->Count()) > 0\">\n      <Output TaskParameter=\"ExitCode\" PropertyName=\"ExecExitCode\"/>\n    </Exec>\n\n    <!--<Exec Command=\"powershell -Command &quot;Start-Sleep -Seconds 10&quot;\" />-->\n\n    <Message Importance=\"High\" Text=\"Electron setup failed!\" Condition=\"'$(ExecExitCode)' != '0'\" />\n\n    <!-- Fix up incorrect symlinks created by npm on Windows when targeting macOS -->\n    <PropertyGroup>\n      <_ElectronFrameworksDir>$(ElectronOutDir)node_modules\\electron\\dist\\Electron.app\\Contents\\Frameworks</_ElectronFrameworksDir>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <_ElectronFrameworkDirs Include=\"$(_ElectronFrameworksDir)\\Electron Framework.framework\" />\n      <_ElectronFrameworkDirs Include=\"$(_ElectronFrameworksDir)\\Mantle.framework\" />\n      <_ElectronFrameworkDirs Include=\"$(_ElectronFrameworksDir)\\ReactiveObjC.framework\" />\n      <_ElectronFrameworkDirs Include=\"$(_ElectronFrameworksDir)\\Squirrel.framework\" />\n    </ItemGroup>\n\n    <!-- Only execute on Windows host when targeting macOS -->\n    <Message Importance=\"High\" Text=\"Fixing macOS framework Resources symlinks\" Condition=\"'$(ElectronPlatform)' == 'mac' AND '$(_CurrentOSPlatform)' == 'win'\" />\n\n    <Exec Command=\"cmd /c del Resources &amp;&amp; mklink /D Resources &quot;Versions\\Current\\Resources&quot;\" WorkingDirectory=\"%(_ElectronFrameworkDirs.Identity)\" Condition=\"'$(ElectronPlatform)' == 'mac' AND '$(_CurrentOSPlatform)' == 'win'\" />\n\n  </Target>\n\n  <Target Name=\"BeforePublishElectronApp\" BeforeTargets=\"PrepareForPublish\">\n\n    <Message Importance=\"High\" Text=\"BeforePublishElectronApp PublishDir: $(PublishDir)\" />\n\n    <PropertyGroup>\n      <_OriginalPublishDir>$(PublishDir)</_OriginalPublishDir>\n      <PublishDir>$(_OriginalPublishDir)bin\\</PublishDir>\n      <DeleteExistingFiles>true</DeleteExistingFiles>\n    </PropertyGroup>\n\n    <Message Importance=\"High\" Text=\"BeforePublishElectronApp PublishDir: $(PublishDir)\" />\n\n  </Target>\n\n\n  <Target Name=\"ElectronFileSystemPublishClearItems\" DependsOnTargets=\"_GatherFilesFromPublishIntermediateOutputPath\">\n\n    <Message Importance=\"High\" Text=\"_PublishIntermediateOutputPathFiles: @(_PublishIntermediateOutputPathFiles)\" />\n    <Message Importance=\"High\" Text=\"_ElectronFilesToCopyWithTargetPath: @(_ElectronFilesToCopyWithTargetPath->'%(TargetPath)')\" />\n\n    <ItemGroup>\n      <_PublishIntermediateOutputPathFiles Remove=\"@(_PublishIntermediateOutputPathFiles)\"></_PublishIntermediateOutputPathFiles>\n    </ItemGroup>\n  </Target>\n\n  <PropertyGroup>\n    <_ElectronPublishAppAfterTarget Condition=\"'$(UsingMicrosoftNETSdkWeb)' == 'true'\">AfterPublish</_ElectronPublishAppAfterTarget>\n    <_ElectronPublishAppAfterTarget Condition=\"'$(UsingMicrosoftNETSdkWeb)' != 'true'\">Publish</_ElectronPublishAppAfterTarget>\n  </PropertyGroup>\n\n  <Target Name=\"ElectronPublishApp\" AfterTargets=\"$(_ElectronPublishAppAfterTarget)\" DependsOnTargets=\"ElectronCheckVersionMismatch\">\n\n    <PropertyGroup>\n      <PublishDir>$(_OriginalPublishDir)</PublishDir>\n      <PublishDir Condition=\"'$(_NonIntermediatePublishDir)' != ''\">$(_NonIntermediatePublishDir)</PublishDir>\n      <ElectronPublishDir>$(_OriginalPublishDir)</ElectronPublishDir>\n    </PropertyGroup>\n\n\n    <Error Condition=\"'$(_IsPlatformMismatch)' == 'true'\"\n           Code=\"ELECTRON100\"\n           Text=\"The target RuntimeIdentifier '$(RuntimeIdentifier)' (platform: $(ElectronPlatform)) does not match the current operating system ($(_CurrentOSPlatform)).\n\nElectron applications must be built on the target operating system:\n- Windows targets (win-x64, win-x86, win-arm64) must be built on Windows\n- Linux targets (linux-x64, linux-arm, linux-arm64) must be built on Linux (or Windows with WSL)\n- macOS targets (osx-x64, osx-arm64) must be built on macOS\n\nEXCEPTION: Linux targets can be built on Windows using WSL (Windows Subsystem for Linux).\n\nFor more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#8-cross-platform-build-validation\" />\n\n    <RemoveEnvironmentVariables Variables=\"BUILD_BUILDNUMBER;BUILD_NUMBER;TRAVIS_BUILD_NUMBER;APPVEYOR_BUILD_NUMBER;CIRCLE_BUILD_NUM;CI_PIPELINE_IID\" />\n\n    <Copy SourceFiles=\"@(ElectronPackageJsonFiles)\" DestinationFiles=\"@(ElectronPackageJsonFiles->'$(ElectronPublishDir)bin\\%(TargetPath)')\" >\n      <Output TaskParameter=\"CopiedFiles\" ItemName=\"CopiedFiles\" />\n    </Copy>\n\n    <Copy SourceFiles=\"@(_ElectronFilesToCopyWithTargetPath)\" DestinationFiles=\"@(_ElectronFilesToCopyWithTargetPath->'$(ElectronPublishDir)bin\\%(TargetPath)')\" >\n      <Output TaskParameter=\"CopiedFiles\" ItemName=\"CopiedFiles\" />\n    </Copy>\n\n    <Message Importance=\"High\" Text=\"_ElectronFilesToCopyWithTargetPath: @(_ElectronFilesToCopyWithTargetPath)\" />\n    <Message Importance=\"High\" Text=\"CopiedFiles: @(CopiedFiles)\" />\n\n\n    <Copy SourceFiles=\"Properties\\$(ElectronBuilderJson)\" DestinationFolder=\"$(ElectronPublishDir)\">\n    </Copy>\n\n    <ItemGroup>\n      <ElectronPublishFilesToMove Include=\"$(ElectronPublishDir)bin\\$(ElectronDirName)\\**\\*.*\" />\n    </ItemGroup>\n    <Message Importance=\"High\" Text=\"ElectronPublishFilesToMove: @(ElectronPublishFilesToMove)\" />\n\n    <ItemGroup>\n      <ElectronPublishFilesToMove Update=\"@(ElectronPublishFilesToMove)\" >\n        <MoveTargetPath>$(ElectronPublishDir)%(RecursiveDir)%(FileName)%(Extension)</MoveTargetPath>\n      </ElectronPublishFilesToMove>\n    </ItemGroup>\n\n    <!--<Message Importance=\"High\" Text=\"ElectronDumpInfo: ElectronPublishFilesToMove\" />\n    <DumpItemMetadataTask Items=\"@(ElectronPublishFilesToMove)\" />-->\n\n    <Move SourceFiles=\"@(ElectronPublishFilesToMove)\" DestinationFiles=\"@(ElectronPublishFilesToMove->'%(MoveTargetPath)')\" />\n\n    <PropertyGroup>\n      <ElectronPublishDirFullPath>$([System.IO.Path]::GetFullPath('$(ElectronPublishDir)'))</ElectronPublishDirFullPath>\n      <ElectronPublishUrlFullPath>$([System.IO.Path]::GetFullPath('$(PublishUrl.TrimEnd(&quot;\\&quot;))'))</ElectronPublishUrlFullPath>\n    </PropertyGroup>\n\n    <PropertyGroup>\n      <IsLinuxWsl>false</IsLinuxWsl>\n      <IsLinuxWsl Condition=\"'$(ElectronPlatform)' == 'linux' AND $([MSBuild]::IsOSPlatform('Windows'))\">true</IsLinuxWsl>\n      <_NpmCmd>npm install electron-builder@$(ElectronBuilderVersion) --save-dev </_NpmCmd>\n      <_NpmCmd Condition=\"'$(IsLinuxWsl)' == 'true'\">wsl bash -ic '$(_NpmCmd)'</_NpmCmd>\n    </PropertyGroup>\n\n    <Message Importance=\"High\" Text=\"ElectronPublishApp: ElectronPublishDirFullPath - $(ElectronPublishDirFullPath)\" />\n\n    <Exec Command=\"$(_NpmCmd)\" WorkingDirectory=\"$(ElectronPublishDirFullPath)\" Timeout=\"600000\" StandardOutputImportance=\"High\" StandardErrorImportance=\"High\" ContinueOnError=\"false\" Condition=\"@(CopiedFiles->Count()) > 0\">\n      <Output TaskParameter=\"ExitCode\" PropertyName=\"ExecExitCode\"/>\n    </Exec>\n\n    <Message Importance=\"High\" Text=\"Electron setup failed!\" Condition=\"'$(ExecExitCode)' != '0'\" />\n\n    <!-- Transform ElectronPublishUrlFullPath to a wslpath if IsLinuxWsl is true -->\n    <Exec Command=\"wsl wslpath '$(ElectronPublishUrlFullPath)'\" ConsoleToMsBuild=\"true\" Condition=\"'$(IsLinuxWsl)' == 'true'\">\n      <Output TaskParameter=\"ConsoleOutput\" PropertyName=\"ElectronPublishUrlFullPath\" />\n    </Exec>\n\n    <PropertyGroup>\n      <ElectronPaParams></ElectronPaParams>\n      <ElectronPaParams Condition=\"'$(ElectronPackageId)' != ''\">$(ElectronPaParams) -c.appId &quot;$(ElectronPackageId)&quot;</ElectronPaParams>\n      <ElectronPaParams Condition=\"'$(Version)' != ''\">$(ElectronPaParams) -c.buildVersion &quot;$(Version)&quot;</ElectronPaParams>\n      <ElectronPaParams Condition=\"'$(Copyright)' != ''\">$(ElectronPaParams) -c.copyright &quot;$(Copyright)&quot;</ElectronPaParams>\n      <ElectronPaParams>$(ElectronPaParams) -c.extraResources &quot;bin/**/*&quot;</ElectronPaParams>\n    </PropertyGroup>\n\n    <PropertyGroup>\n      <_NpxCmd>npx electron-builder --config=./$(ElectronBuilderJson) --$(ElectronPlatform) --$(ElectronArch) -c.electronVersion=$(ElectronVersion) -c.directories.output &quot;$(ElectronPublishUrlFullPath)&quot; $(ElectronPaParams)</_NpxCmd>\n      <_NpxCmd Condition=\"'$(IsLinuxWsl)' == 'true'\">wsl bash -ic '$(_NpxCmd)'</_NpxCmd>\n    </PropertyGroup>\n\n    <Exec Command=\"$(_NpxCmd)\" WorkingDirectory=\"$(ElectronPublishDirFullPath)\" Timeout=\"1800000\" StandardOutputImportance=\"High\" StandardErrorImportance=\"High\" ContinueOnError=\"false\" Condition=\"@(CopiedFiles->Count()) > 0\">\n      <Output TaskParameter=\"ExitCode\" PropertyName=\"ExecExitCode\"/>\n    </Exec>\n\n    <Message Importance=\"High\" Text=\"Electron setup failed!\" Condition=\"'$(ExecExitCode)' != '0'\" />\n\n  </Target>\n\n <Import Project=\"$(MSBuildThisFileDirectory)ElectronNET.DesignTime.targets\" Condition=\"'$(MSBuildRuntimeType)' == 'Full' and '$(BuildingInsideVisualStudio)' == 'true'\"/>\n\n</Project>\n"
  },
  {
    "path": "src/ElectronNET/build/ElectronNET.MigrationChecks.targets",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <PropertyGroup>\n    <ElectronMigrationChecksDependsOn>\n      ElectronCheckNoPackageJson;\n      ElectronCheckRootPackageJsonNoElectron;\n      ElectronCheckRootPackageJsonNotCopied;\n      ElectronCheckNoManifestJson;\n      ElectronCheckElectronBuilderJson;\n      ElectronCheckNoParentPaths;\n      ElectronCheckPubxmlFiles\n    </ElectronMigrationChecksDependsOn>\n  </PropertyGroup>\n\n  <!-- Main migration checks target that runs before build -->\n  <Target Name=\"ElectronMigrationChecks\"\n          BeforeTargets=\"BeforeBuild\"\n          DependsOnTargets=\"$(ElectronMigrationChecksDependsOn)\"\n          Condition=\"'$(ElectronSkipMigrationChecks)' != 'true'\">\n  </Target>\n\n  <!--\n    Check 1: No package.json/package-lock.json must be present in the project (except ElectronHostHook folder)\n\n    NOTE: Root package.json is excluded from ELECTRON001 and checked by separate targets.\n  -->\n  <Target Name=\"ElectronCheckNoPackageJson\">\n\n    <!-- Find all package.json files, excluding ElectronHostHook folder, root, and output directories -->\n    <ItemGroup>\n      <_InvalidPackageJson Include=\"$(MSBuildProjectDirectory)\\**\\package.json\"\n                           Exclude=\"$(MSBuildProjectDirectory)\\package.json;\n                                    $(MSBuildProjectDirectory)\\ElectronHostHook\\**\\package.json;\n                                    $(MSBuildProjectDirectory)\\bin\\**\\package.json;\n                                    $(MSBuildProjectDirectory)\\obj\\**\\package.json;\n                                    $(MSBuildProjectDirectory)\\publish\\**\\package.json;\n                                    $(MSBuildProjectDirectory)\\node_modules\\**\\package.json\" />\n      <_InvalidPackageLockJson Include=\"$(MSBuildProjectDirectory)\\**\\package-lock.json\"\n                               Exclude=\"$(MSBuildProjectDirectory)\\ElectronHostHook\\**\\package-lock.json;\n                                        $(MSBuildProjectDirectory)\\bin\\**\\package-lock.json;\n                                        $(MSBuildProjectDirectory)\\obj\\**\\package-lock.json;\n                                        $(MSBuildProjectDirectory)\\publish\\**\\package-lock.json;\n                                        $(MSBuildProjectDirectory)\\node_modules\\**\\package-lock.json\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n      <_HasInvalidPackageJson>false</_HasInvalidPackageJson>\n      <_HasInvalidPackageJson Condition=\"@(_InvalidPackageJson->Count()) > 0 OR @(_InvalidPackageLockJson->Count()) > 0\">true</_HasInvalidPackageJson>\n    </PropertyGroup>\n\n    <Warning Condition=\"'$(_HasInvalidPackageJson)' == 'true'\"\n             Code=\"ELECTRON001\"\n             Text=\"Found package.json or package-lock.json file(s) in unsupported location(s). These files are no longer supported in this location.\n\nFiles found:\n@(_InvalidPackageJson, '%0A')@(_InvalidPackageLockJson, '%0A')\n\nMIGRATION REQUIRED:\nAll Electron.NET-related properties from an existing package.json must now be specified as MSBuild properties in the project file.\n\nFor more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#1-packagejson-not-allowed\n\nEXCEPTION:\n- package.json and package-lock.json files ARE allowed in the 'ElectronHostHook' folder for custom host hook implementations.\n- A package.json in the project root is handled by separate migration checks.\" />\n\n  </Target>\n\n  <!--\n    Check 1b: Root package.json must not contain Electron-related configuration\n  -->\n  <Target Name=\"ElectronCheckRootPackageJsonNoElectron\"\n          Condition=\"Exists('$(MSBuildProjectDirectory)\\package.json')\">\n\n    <ItemGroup>\n      <_RootPackageJsonLines Include=\"$([System.IO.File]::ReadAllLines('$(MSBuildProjectDirectory)\\package.json'))\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n      <_RootPackageJsonContent>@(_RootPackageJsonLines, ' ')</_RootPackageJsonContent>\n      <_RootPackageJsonHasElectron>false</_RootPackageJsonHasElectron>\n      <_RootPackageJsonHasElectron Condition=\"$([System.Text.RegularExpressions.Regex]::IsMatch('$(_RootPackageJsonContent)', 'electron', System.Text.RegularExpressions.RegexOptions.IgnoreCase))\">true</_RootPackageJsonHasElectron>\n    </PropertyGroup>\n\n    <Warning\n      Condition=\"'$(_RootPackageJsonHasElectron)' == 'true'\"\n      Code=\"ELECTRON008\"\n      Text=\"The project contains a root package.json that references 'electron' (case-insensitive).\n\nFile:\n$(MSBuildProjectDirectory)\\package.json\n\nMIGRATION REQUIRED:\nElectron.NET configuration must be defined via MSBuild properties and electron-builder.json (not via a user-provided package.json).\n\nHOW TO FIX:\n- Remove Electron-related entries from the root package.json, or delete the file if it's only used for Electron configuration.\n\nFor more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#1-packagejson-not-allowed\" />\n\n  </Target>\n\n  <!--\n    Check 1c: Root package.json must not be copied to output/publish\n  -->\n  <Target Name=\"ElectronCheckRootPackageJsonNotCopied\"\n          Condition=\"Exists('$(MSBuildProjectDirectory)\\package.json')\">\n\n    <ItemGroup>\n      <_RootPackageJsonFile Include=\"@(Content);@(None)\"\n                              Condition=\"'%(Identity)' == 'package.json' OR '%(Identity)' == '$(MSBuildProjectDirectory)\\package.json'\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n      <_RootPackageJsonIsCopied>false</_RootPackageJsonIsCopied>\n      <_RootPackageJsonIsCopied Condition=\"'@(_RootPackageJsonFile)' != '' AND ( '%(_RootPackageJsonFile.CopyToOutputDirectory)' != '' OR '%(_RootPackageJsonFile.CopyToPublishDirectory)' != '' )\">true</_RootPackageJsonIsCopied>\n    </PropertyGroup>\n\n    <Warning\n      Condition=\"'$(_RootPackageJsonIsCopied)' == 'true'\"\n      Code=\"ELECTRON009\"\n      Text=\"The project contains a root package.json that is configured to be copied to the output/publish directory.\n\nFile:\n$(MSBuildProjectDirectory)\\package.json\n\nMIGRATION REQUIRED:\nRoot package.json must not be copied during build/publish.\n\nHOW TO FIX:\n- Remove CopyToOutputDirectory / CopyToPublishDirectory metadata for package.json in your project file.\n\nFor more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#1-packagejson-not-allowed\" />\n\n  </Target>\n\n  <!--\n    Check 2: No electron-manifest.json must be present in the project\n  -->\n  <Target Name=\"ElectronCheckNoManifestJson\">\n\n    <ItemGroup>\n      <_InvalidManifestJson Include=\"$(MSBuildProjectDirectory)\\**\\electron.manifest.json;$(MSBuildProjectDirectory)\\**\\electron-manifest.json\"\n                            Exclude=\"$(MSBuildProjectDirectory)\\bin\\**\\*;\n                                     $(MSBuildProjectDirectory)\\obj\\**\\*;\n                                     $(MSBuildProjectDirectory)\\publish\\**\\*;\n                                     $(MSBuildProjectDirectory)\\node_modules\\**\\*\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n      <_HasInvalidManifestJson>false</_HasInvalidManifestJson>\n      <_HasInvalidManifestJson Condition=\"@(_InvalidManifestJson->Count()) > 0\">true</_HasInvalidManifestJson>\n    </PropertyGroup>\n\n    <Warning Condition=\"'$(_HasInvalidManifestJson)' == 'true'\"\n             Code=\"ELECTRON002\"\n             Text=\"Found electron-manifest.json file(s) in the project. This file format is no longer supported.\n\nFiles found:\n@(_InvalidManifestJson, '%0A')\n\nMIGRATION REQUIRED:\n1. All properties from an existing electron-manifest.json file must now be specified as MSBuild properties in the project file.\n   For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#2-electron-manifestjson-not-allowed\n\n2. The subtree from the 'build' property must be moved to the electron-builder.json file inside the './Properties' folder.\n   For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#3-electron-builderjson-location\" />\n\n  </Target>\n\n  <!--\n    Check 3: Single electron-builder.json must exist in ./Properties folder\n  -->\n  <Target Name=\"ElectronCheckElectronBuilderJson\">\n\n    <!-- Check for electron-builder.json in the Properties folder -->\n    <ItemGroup>\n      <_ElectronBuilderJsonInProperties Include=\"$(MSBuildProjectDirectory)\\Properties\\electron-builder.json\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n      <_HasElectronBuilderJsonInProperties>false</_HasElectronBuilderJsonInProperties>\n      <_HasElectronBuilderJsonInProperties Condition=\"Exists('$(MSBuildProjectDirectory)\\Properties\\electron-builder.json')\">true</_HasElectronBuilderJsonInProperties>\n    </PropertyGroup>\n\n    <!-- Check for electron-builder.json in wrong locations -->\n    <ItemGroup>\n      <_ElectronBuilderJsonWrongLocation Include=\"$(MSBuildProjectDirectory)\\**\\electron-builder.json\"\n                                          Exclude=\"$(MSBuildProjectDirectory)\\Properties\\electron-builder.json;\n                                                   $(MSBuildProjectDirectory)\\bin\\**\\*;\n                                                   $(MSBuildProjectDirectory)\\obj\\**\\*;\n                                                   $(MSBuildProjectDirectory)\\publish\\**\\*;\n                                                   $(MSBuildProjectDirectory)\\node_modules\\**\\*\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n      <_HasElectronBuilderJsonWrongLocation>false</_HasElectronBuilderJsonWrongLocation>\n      <_HasElectronBuilderJsonWrongLocation Condition=\"@(_ElectronBuilderJsonWrongLocation->Count()) > 0\">true</_HasElectronBuilderJsonWrongLocation>\n    </PropertyGroup>\n\n    <Warning Condition=\"'$(_HasElectronBuilderJsonInProperties)' != 'true'\"\n             Code=\"ELECTRON003\"\n             Text=\"The project must contain an electron-builder.json file inside the './Properties' folder.\n\nExpected location: $(MSBuildProjectDirectory)\\Properties\\electron-builder.json\n\nREQUIRED ACTION:\nCreate an electron-builder.json file in the Properties folder with your electron-builder configuration.\nFor more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#3-electron-builderjson-location\" />\n\n    <Warning Condition=\"'$(_HasElectronBuilderJsonWrongLocation)' == 'true'\"\n             Code=\"ELECTRON004\"\n             Text=\"Found electron-builder.json file(s) in incorrect location(s). The file must be located only in the './Properties' folder.\n\nFiles found in wrong locations:\n@(_ElectronBuilderJsonWrongLocation, '%0A')\n\nREQUIRED ACTION:\nMove the electron-builder.json file to: $(MSBuildProjectDirectory)\\Properties\\electron-builder.json\" />\n\n  </Target>\n\n  <!--\n    Check 4: No parent-path references (..) in electron-builder.json\n  -->\n  <Target Name=\"ElectronCheckNoParentPaths\"\n          Condition=\"Exists('$(MSBuildProjectDirectory)\\Properties\\electron-builder.json')\">\n\n    <PropertyGroup>\n      <_ElectronBuilderJsonPath>$(MSBuildProjectDirectory)\\Properties\\electron-builder.json</_ElectronBuilderJsonPath>\n    </PropertyGroup>\n\n    <!-- Read the file content -->\n    <ReadLinesFromFile File=\"$(_ElectronBuilderJsonPath)\">\n      <Output TaskParameter=\"Lines\" ItemName=\"_ElectronBuilderJsonLines\" />\n    </ReadLinesFromFile>\n\n    <!-- Check if any line contains parent path references -->\n    <PropertyGroup>\n      <_ElectronBuilderJsonContent>@(_ElectronBuilderJsonLines, ' ')</_ElectronBuilderJsonContent>\n      <_HasParentPathReference>false</_HasParentPathReference>\n      <_HasParentPathReference Condition=\"$(_ElectronBuilderJsonContent.Contains('../')) OR $(_ElectronBuilderJsonContent.Contains('..\\\\'))\" >true</_HasParentPathReference>\n    </PropertyGroup>\n\n    <Warning Condition=\"'$(_HasParentPathReference)' == 'true'\"\n             Code=\"ELECTRON005\"\n             Text=\"The electron-builder.json file contains parent-path references ('..').\n\nFile: $(_ElectronBuilderJsonPath)\n\nMIGRATION REQUIRED:\nParent-path references are not allowed in electron-builder.json because the file is copied to the build output directory during publishing.\n\nHOW TO FIX:\n1. Place any resource files (icons, installers, etc.) inside your project folder structure\n2. Configure those files to be copied to the output directory using the project file:\n   \n   &lt;ItemGroup&gt;\n     &lt;Content Include=&quot;Assets\\**\\*&quot;&gt;\n       &lt;CopyToOutputDirectory&gt;PreserveNewest&lt;/CopyToOutputDirectory&gt;\n     &lt;/Content&gt;\n   &lt;/ItemGroup&gt;\n\n3. Reference files using relative paths from the output directory (e.g., 'Assets/myicon.ico' instead of '../Assets/myicon.ico')\n\nFor more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#4-parent-paths-not-allowed-in-electron-builderjson\" />\n\n  </Target>\n\n  <!--\n    Check 5: Pubxml files match the project type\n    \n    This check validates that publish profiles are appropriate for the project type:\n    - ASP.NET projects (using Microsoft.NET.Sdk.Web) have WebPublishMethod in their pubxml files\n    - Console/other projects PublishProtocol instead of WebPublishMethod\n  -->\n  <Target Name=\"ElectronCheckPubxmlFiles\">\n\n    <!-- Find all pubxml files -->\n    <ItemGroup>\n      <_PubxmlFiles Include=\"$(MSBuildProjectDirectory)\\Properties\\PublishProfiles\\*.pubxml\" />\n    </ItemGroup>\n\n    <!-- Determine if this is an ASP.NET project (UsingMicrosoftNETSdkWeb is set by the Web SDK) -->\n    <PropertyGroup>\n      <_IsAspNetProject>false</_IsAspNetProject>\n      <_IsAspNetProject Condition=\"'$(UsingMicrosoftNETSdkWeb)' == 'true'\">true</_IsAspNetProject>\n      <_HasPubxmlFiles>false</_HasPubxmlFiles>\n      <_HasPubxmlFiles Condition=\"@(_PubxmlFiles->Count()) > 0\">true</_HasPubxmlFiles>\n    </PropertyGroup>\n\n    <!-- Build a combined content string for each file and check (only if files exist) -->\n    <ItemGroup Condition=\"'$(_HasPubxmlFiles)' == 'true'\">\n      <_PubxmlFileInfo Include=\"@(_PubxmlFiles)\" Condition=\"'%(Identity)' != ''\">\n        <FileContent>$([System.IO.File]::ReadAllText('%(Identity)'))</FileContent>\n      </_PubxmlFileInfo>\n    </ItemGroup>\n\n    <!-- Check each file for WebPublishMethod presence -->\n    <ItemGroup Condition=\"'$(_HasPubxmlFiles)' == 'true'\">\n      <_PubxmlFileInfoWithFlags Include=\"@(_PubxmlFileInfo)\" Condition=\"'%(Identity)' != ''\">\n        <HasWebPublishMethod>$([System.Text.RegularExpressions.Regex]::IsMatch('%(FileContent)', '&lt;WebPublishMethod&gt;'))</HasWebPublishMethod>\n      </_PubxmlFileInfoWithFlags>\n    </ItemGroup>\n\n    <!-- For ASP.NET projects: find pubxml files MISSING WebPublishMethod -->\n    <ItemGroup>\n      <_AspNetMissingWebPublishMethod Include=\"@(_PubxmlFileInfoWithFlags)\"\n                                       Condition=\"'$(_IsAspNetProject)' == 'true' AND '%(HasWebPublishMethod)' == 'False'\" />\n    </ItemGroup>\n\n    <!-- For Console/Non-ASP.NET projects: find pubxml files that HAVE WebPublishMethod -->\n    <ItemGroup>\n      <_ConsolePubxmlWithAspNetProperties Include=\"@(_PubxmlFileInfoWithFlags)\"\n                                           Condition=\"'$(_IsAspNetProject)' != 'true' AND '%(HasWebPublishMethod)' == 'True'\" />\n    </ItemGroup>\n\n    <!-- Warning for ASP.NET projects with incorrect pubxml files -->\n    <Warning\n      Condition=\"'@(_AspNetMissingWebPublishMethod)' != ''\"\n      Code=\"ELECTRON006\"\n      Text=\"The publish profile '%(_AspNetMissingWebPublishMethod.Identity)' appears to be configured for a console application (missing WebPublishMethod property), but this is an ASP.NET project.\n\nRECOMMENDED ACTION:\n1. Delete the existing publish profiles\n2. Use the Visual Studio Publishing Wizard to create a new profile:\n   - Right-click on the project in Solution Explorer\n   - Select 'Publish...'\n   - Follow the wizard to create a Folder publish profile for ASP.NET\n\nNote: ASP.NET Electron.NET projects require publish profiles with WebPublishMethod set to FileSystem.\n\nFor more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#5-publish-profile-validation\" />\n\n    <!-- Warning for Console projects with incorrect pubxml files -->\n    <Warning\n      Condition=\"'@(_ConsolePubxmlWithAspNetProperties)' != ''\"\n      Code=\"ELECTRON007\"\n      Text=\"The publish profile '%(_ConsolePubxmlWithAspNetProperties.Identity)' appears to be configured for ASP.NET publishing (containing the WebPublishMethod property), but this is a console application project.\n\nRECOMMENDED ACTION:\n1. Delete the existing publish profiles\n2. Use the Visual Studio Publishing Wizard to create a new profile:\n   - Right-click on the project in Solution Explorer\n   - Select 'Publish...'\n   - Follow the wizard to create a Folder publish profile for console applications\n\nNote: Console Electron.NET projects should not use ASP.NET-style publish profiles.\n\nFor more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#5-publish-profile-validation\" />\n\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "src/ElectronNET/build/ElectronNETRules.Project.xaml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Rule Name=\"ElectronNet\" \n      DisplayName=\"Electron.NET\" \n      Order=\"1\" \n      PageTemplate=\"generic\" \n      xmlns=\"http://schemas.microsoft.com/build/2009/properties\">\n\n  <Rule.Categories>\n    <Category Name=\"General\" DisplayName=\"General\" />\n    <Category Name=\"AppInfo\" DisplayName=\"Application Info\" />\n    <Category Name=\"Auxiliary\" DisplayName=\"Aux\" />\n  </Rule.Categories>\n\n  <Rule.DataSource>\n    <DataSource Persistence=\"ProjectFile\" Label=\"ElectronNetCommon\" HasConfigurationCondition=\"False\" />\n  </Rule.DataSource>\n\n  <!--General Category -->\n\n  <EnumProperty Name=\"ElectronVersion\"\n                DisplayName=\"Electron Version\"\n                Description=\"The version of Electron to use for building (full semver)\"\n                Category=\"General\">\n    <!-- Auto-generated list of stable Electron releases -->\n    <EnumValue Name=\"23.0.0\" DisplayName=\"23.0.0\" />\n    <EnumValue Name=\"23.1.0\" DisplayName=\"23.1.0\" />\n    <EnumValue Name=\"23.1.1\" DisplayName=\"23.1.1\" />\n    <EnumValue Name=\"23.1.2\" DisplayName=\"23.1.2\" />\n    <EnumValue Name=\"23.1.3\" DisplayName=\"23.1.3\" />\n    <EnumValue Name=\"23.1.4\" DisplayName=\"23.1.4\" />\n    <EnumValue Name=\"23.2.0\" DisplayName=\"23.2.0\" />\n    <EnumValue Name=\"23.2.1\" DisplayName=\"23.2.1\" />\n    <EnumValue Name=\"23.2.2\" DisplayName=\"23.2.2\" />\n    <EnumValue Name=\"23.2.3\" DisplayName=\"23.2.3\" />\n    <EnumValue Name=\"23.2.4\" DisplayName=\"23.2.4\" />\n    <EnumValue Name=\"23.3.0\" DisplayName=\"23.3.0\" />\n    <EnumValue Name=\"23.3.1\" DisplayName=\"23.3.1\" />\n    <EnumValue Name=\"23.3.2\" DisplayName=\"23.3.2\" />\n    <EnumValue Name=\"23.3.3\" DisplayName=\"23.3.3\" />\n    <EnumValue Name=\"23.3.4\" DisplayName=\"23.3.4\" />\n    <EnumValue Name=\"23.3.5\" DisplayName=\"23.3.5\" />\n    <EnumValue Name=\"23.3.6\" DisplayName=\"23.3.6\" />\n    <EnumValue Name=\"23.3.7\" DisplayName=\"23.3.7\" />\n    <EnumValue Name=\"23.3.8\" DisplayName=\"23.3.8\" />\n    <EnumValue Name=\"23.3.9\" DisplayName=\"23.3.9\" />\n    <EnumValue Name=\"23.3.10\" DisplayName=\"23.3.10\" />\n    <EnumValue Name=\"23.3.11\" DisplayName=\"23.3.11\" />\n    <EnumValue Name=\"23.3.12\" DisplayName=\"23.3.12\" />\n    <EnumValue Name=\"23.3.13\" DisplayName=\"23.3.13\" />\n    <EnumValue Name=\"24.0.0\" DisplayName=\"24.0.0\" />\n    <EnumValue Name=\"24.1.0\" DisplayName=\"24.1.0\" />\n    <EnumValue Name=\"24.1.1\" DisplayName=\"24.1.1\" />\n    <EnumValue Name=\"24.1.2\" DisplayName=\"24.1.2\" />\n    <EnumValue Name=\"24.1.3\" DisplayName=\"24.1.3\" />\n    <EnumValue Name=\"24.2.0\" DisplayName=\"24.2.0\" />\n    <EnumValue Name=\"24.3.0\" DisplayName=\"24.3.0\" />\n    <EnumValue Name=\"24.3.1\" DisplayName=\"24.3.1\" />\n    <EnumValue Name=\"24.4.0\" DisplayName=\"24.4.0\" />\n    <EnumValue Name=\"24.4.1\" DisplayName=\"24.4.1\" />\n    <EnumValue Name=\"24.5.0\" DisplayName=\"24.5.0\" />\n    <EnumValue Name=\"24.5.1\" DisplayName=\"24.5.1\" />\n    <EnumValue Name=\"24.6.0\" DisplayName=\"24.6.0\" />\n    <EnumValue Name=\"24.6.1\" DisplayName=\"24.6.1\" />\n    <EnumValue Name=\"24.6.2\" DisplayName=\"24.6.2\" />\n    <EnumValue Name=\"24.6.3\" DisplayName=\"24.6.3\" />\n    <EnumValue Name=\"24.6.4\" DisplayName=\"24.6.4\" />\n    <EnumValue Name=\"24.6.5\" DisplayName=\"24.6.5\" />\n    <EnumValue Name=\"24.7.0\" DisplayName=\"24.7.0\" />\n    <EnumValue Name=\"24.7.1\" DisplayName=\"24.7.1\" />\n    <EnumValue Name=\"24.8.0\" DisplayName=\"24.8.0\" />\n    <EnumValue Name=\"24.8.1\" DisplayName=\"24.8.1\" />\n    <EnumValue Name=\"24.8.2\" DisplayName=\"24.8.2\" />\n    <EnumValue Name=\"24.8.3\" DisplayName=\"24.8.3\" />\n    <EnumValue Name=\"24.8.4\" DisplayName=\"24.8.4\" />\n    <EnumValue Name=\"24.8.5\" DisplayName=\"24.8.5\" />\n    <EnumValue Name=\"24.8.6\" DisplayName=\"24.8.6\" />\n    <EnumValue Name=\"24.8.7\" DisplayName=\"24.8.7\" />\n    <EnumValue Name=\"24.8.8\" DisplayName=\"24.8.8\" />\n    <EnumValue Name=\"25.0.0\" DisplayName=\"25.0.0\" />\n    <EnumValue Name=\"25.0.1\" DisplayName=\"25.0.1\" />\n    <EnumValue Name=\"25.1.0\" DisplayName=\"25.1.0\" />\n    <EnumValue Name=\"25.1.1\" DisplayName=\"25.1.1\" />\n    <EnumValue Name=\"25.2.0\" DisplayName=\"25.2.0\" />\n    <EnumValue Name=\"25.3.0\" DisplayName=\"25.3.0\" />\n    <EnumValue Name=\"25.3.1\" DisplayName=\"25.3.1\" />\n    <EnumValue Name=\"25.3.2\" DisplayName=\"25.3.2\" />\n    <EnumValue Name=\"25.4.0\" DisplayName=\"25.4.0\" />\n    <EnumValue Name=\"25.5.0\" DisplayName=\"25.5.0\" />\n    <EnumValue Name=\"25.6.0\" DisplayName=\"25.6.0\" />\n    <EnumValue Name=\"25.7.0\" DisplayName=\"25.7.0\" />\n    <EnumValue Name=\"25.8.0\" DisplayName=\"25.8.0\" />\n    <EnumValue Name=\"25.8.1\" DisplayName=\"25.8.1\" />\n    <EnumValue Name=\"25.8.2\" DisplayName=\"25.8.2\" />\n    <EnumValue Name=\"25.8.3\" DisplayName=\"25.8.3\" />\n    <EnumValue Name=\"25.8.4\" DisplayName=\"25.8.4\" />\n    <EnumValue Name=\"25.9.0\" DisplayName=\"25.9.0\" />\n    <EnumValue Name=\"25.9.1\" DisplayName=\"25.9.1\" />\n    <EnumValue Name=\"25.9.2\" DisplayName=\"25.9.2\" />\n    <EnumValue Name=\"25.9.3\" DisplayName=\"25.9.3\" />\n    <EnumValue Name=\"25.9.4\" DisplayName=\"25.9.4\" />\n    <EnumValue Name=\"25.9.5\" DisplayName=\"25.9.5\" />\n    <EnumValue Name=\"25.9.6\" DisplayName=\"25.9.6\" />\n    <EnumValue Name=\"25.9.7\" DisplayName=\"25.9.7\" />\n    <EnumValue Name=\"25.9.8\" DisplayName=\"25.9.8\" />\n    <EnumValue Name=\"26.0.0\" DisplayName=\"26.0.0\" />\n    <EnumValue Name=\"26.1.0\" DisplayName=\"26.1.0\" />\n    <EnumValue Name=\"26.2.0\" DisplayName=\"26.2.0\" />\n    <EnumValue Name=\"26.2.1\" DisplayName=\"26.2.1\" />\n    <EnumValue Name=\"26.2.2\" DisplayName=\"26.2.2\" />\n    <EnumValue Name=\"26.2.3\" DisplayName=\"26.2.3\" />\n    <EnumValue Name=\"26.2.4\" DisplayName=\"26.2.4\" />\n    <EnumValue Name=\"26.3.0\" DisplayName=\"26.3.0\" />\n    <EnumValue Name=\"26.4.0\" DisplayName=\"26.4.0\" />\n    <EnumValue Name=\"26.4.1\" DisplayName=\"26.4.1\" />\n    <EnumValue Name=\"26.4.2\" DisplayName=\"26.4.2\" />\n    <EnumValue Name=\"26.4.3\" DisplayName=\"26.4.3\" />\n    <EnumValue Name=\"26.5.0\" DisplayName=\"26.5.0\" />\n    <EnumValue Name=\"26.6.0\" DisplayName=\"26.6.0\" />\n    <EnumValue Name=\"26.6.1\" DisplayName=\"26.6.1\" />\n    <EnumValue Name=\"26.6.2\" DisplayName=\"26.6.2\" />\n    <EnumValue Name=\"26.6.3\" DisplayName=\"26.6.3\" />\n    <EnumValue Name=\"26.6.4\" DisplayName=\"26.6.4\" />\n    <EnumValue Name=\"26.6.5\" DisplayName=\"26.6.5\" />\n    <EnumValue Name=\"26.6.6\" DisplayName=\"26.6.6\" />\n    <EnumValue Name=\"26.6.7\" DisplayName=\"26.6.7\" />\n    <EnumValue Name=\"26.6.8\" DisplayName=\"26.6.8\" />\n    <EnumValue Name=\"26.6.9\" DisplayName=\"26.6.9\" />\n    <EnumValue Name=\"26.6.10\" DisplayName=\"26.6.10\" />\n    <EnumValue Name=\"27.0.0\" DisplayName=\"27.0.0\" />\n    <EnumValue Name=\"27.0.1\" DisplayName=\"27.0.1\" />\n    <EnumValue Name=\"27.0.2\" DisplayName=\"27.0.2\" />\n    <EnumValue Name=\"27.0.3\" DisplayName=\"27.0.3\" />\n    <EnumValue Name=\"27.0.4\" DisplayName=\"27.0.4\" />\n    <EnumValue Name=\"27.1.0\" DisplayName=\"27.1.0\" />\n    <EnumValue Name=\"27.1.2\" DisplayName=\"27.1.2\" />\n    <EnumValue Name=\"27.1.3\" DisplayName=\"27.1.3\" />\n    <EnumValue Name=\"27.2.0\" DisplayName=\"27.2.0\" />\n    <EnumValue Name=\"27.2.1\" DisplayName=\"27.2.1\" />\n    <EnumValue Name=\"27.2.2\" DisplayName=\"27.2.2\" />\n    <EnumValue Name=\"27.2.3\" DisplayName=\"27.2.3\" />\n    <EnumValue Name=\"27.2.4\" DisplayName=\"27.2.4\" />\n    <EnumValue Name=\"27.3.0\" DisplayName=\"27.3.0\" />\n    <EnumValue Name=\"27.3.1\" DisplayName=\"27.3.1\" />\n    <EnumValue Name=\"27.3.2\" DisplayName=\"27.3.2\" />\n    <EnumValue Name=\"27.3.3\" DisplayName=\"27.3.3\" />\n    <EnumValue Name=\"27.3.4\" DisplayName=\"27.3.4\" />\n    <EnumValue Name=\"27.3.5\" DisplayName=\"27.3.5\" />\n    <EnumValue Name=\"27.3.6\" DisplayName=\"27.3.6\" />\n    <EnumValue Name=\"27.3.7\" DisplayName=\"27.3.7\" />\n    <EnumValue Name=\"27.3.8\" DisplayName=\"27.3.8\" />\n    <EnumValue Name=\"27.3.9\" DisplayName=\"27.3.9\" />\n    <EnumValue Name=\"27.3.10\" DisplayName=\"27.3.10\" />\n    <EnumValue Name=\"27.3.11\" DisplayName=\"27.3.11\" />\n    <EnumValue Name=\"28.0.0\" DisplayName=\"28.0.0\" />\n    <EnumValue Name=\"28.1.0\" DisplayName=\"28.1.0\" />\n    <EnumValue Name=\"28.1.1\" DisplayName=\"28.1.1\" />\n    <EnumValue Name=\"28.1.2\" DisplayName=\"28.1.2\" />\n    <EnumValue Name=\"28.1.3\" DisplayName=\"28.1.3\" />\n    <EnumValue Name=\"28.1.4\" DisplayName=\"28.1.4\" />\n    <EnumValue Name=\"28.2.0\" DisplayName=\"28.2.0\" />\n    <EnumValue Name=\"28.2.1\" DisplayName=\"28.2.1\" />\n    <EnumValue Name=\"28.2.2\" DisplayName=\"28.2.2\" />\n    <EnumValue Name=\"28.2.3\" DisplayName=\"28.2.3\" />\n    <EnumValue Name=\"28.2.4\" DisplayName=\"28.2.4\" />\n    <EnumValue Name=\"28.2.5\" DisplayName=\"28.2.5\" />\n    <EnumValue Name=\"28.2.6\" DisplayName=\"28.2.6\" />\n    <EnumValue Name=\"28.2.7\" DisplayName=\"28.2.7\" />\n    <EnumValue Name=\"28.2.8\" DisplayName=\"28.2.8\" />\n    <EnumValue Name=\"28.2.9\" DisplayName=\"28.2.9\" />\n    <EnumValue Name=\"28.2.10\" DisplayName=\"28.2.10\" />\n    <EnumValue Name=\"28.3.0\" DisplayName=\"28.3.0\" />\n    <EnumValue Name=\"28.3.1\" DisplayName=\"28.3.1\" />\n    <EnumValue Name=\"28.3.2\" DisplayName=\"28.3.2\" />\n    <EnumValue Name=\"28.3.3\" DisplayName=\"28.3.3\" />\n    <EnumValue Name=\"29.0.0\" DisplayName=\"29.0.0\" />\n    <EnumValue Name=\"29.0.1\" DisplayName=\"29.0.1\" />\n    <EnumValue Name=\"29.1.0\" DisplayName=\"29.1.0\" />\n    <EnumValue Name=\"29.1.1\" DisplayName=\"29.1.1\" />\n    <EnumValue Name=\"29.1.2\" DisplayName=\"29.1.2\" />\n    <EnumValue Name=\"29.1.3\" DisplayName=\"29.1.3\" />\n    <EnumValue Name=\"29.1.4\" DisplayName=\"29.1.4\" />\n    <EnumValue Name=\"29.1.5\" DisplayName=\"29.1.5\" />\n    <EnumValue Name=\"29.1.6\" DisplayName=\"29.1.6\" />\n    <EnumValue Name=\"29.2.0\" DisplayName=\"29.2.0\" />\n    <EnumValue Name=\"29.3.0\" DisplayName=\"29.3.0\" />\n    <EnumValue Name=\"29.3.1\" DisplayName=\"29.3.1\" />\n    <EnumValue Name=\"29.3.2\" DisplayName=\"29.3.2\" />\n    <EnumValue Name=\"29.3.3\" DisplayName=\"29.3.3\" />\n    <EnumValue Name=\"29.4.0\" DisplayName=\"29.4.0\" />\n    <EnumValue Name=\"29.4.1\" DisplayName=\"29.4.1\" />\n    <EnumValue Name=\"29.4.2\" DisplayName=\"29.4.2\" />\n    <EnumValue Name=\"29.4.3\" DisplayName=\"29.4.3\" />\n    <EnumValue Name=\"29.4.4\" DisplayName=\"29.4.4\" />\n    <EnumValue Name=\"29.4.5\" DisplayName=\"29.4.5\" />\n    <EnumValue Name=\"29.4.6\" DisplayName=\"29.4.6\" />\n    <EnumValue Name=\"30.0.0\" DisplayName=\"30.0.0\" />\n    <EnumValue Name=\"30.0.1\" DisplayName=\"30.0.1\" />\n    <EnumValue Name=\"30.0.2\" DisplayName=\"30.0.2\" />\n    <EnumValue Name=\"30.0.3\" DisplayName=\"30.0.3\" />\n    <EnumValue Name=\"30.0.4\" DisplayName=\"30.0.4\" />\n    <EnumValue Name=\"30.0.5\" DisplayName=\"30.0.5\" />\n    <EnumValue Name=\"30.0.6\" DisplayName=\"30.0.6\" />\n    <EnumValue Name=\"30.0.7\" DisplayName=\"30.0.7\" />\n    <EnumValue Name=\"30.0.8\" DisplayName=\"30.0.8\" />\n    <EnumValue Name=\"30.0.9\" DisplayName=\"30.0.9\" />\n    <EnumValue Name=\"30.1.0\" DisplayName=\"30.1.0\" />\n    <EnumValue Name=\"30.1.1\" DisplayName=\"30.1.1\" />\n    <EnumValue Name=\"30.1.2\" DisplayName=\"30.1.2\" />\n    <EnumValue Name=\"30.2.0\" DisplayName=\"30.2.0\" />\n    <EnumValue Name=\"30.3.0\" DisplayName=\"30.3.0\" />\n    <EnumValue Name=\"30.3.1\" DisplayName=\"30.3.1\" />\n    <EnumValue Name=\"30.4.0\" DisplayName=\"30.4.0\" />\n    <EnumValue Name=\"30.5.0\" DisplayName=\"30.5.0\" />\n    <EnumValue Name=\"30.5.1\" DisplayName=\"30.5.1\" />\n    <EnumValue Name=\"31.0.0\" DisplayName=\"31.0.0\" />\n    <EnumValue Name=\"31.0.1\" DisplayName=\"31.0.1\" />\n    <EnumValue Name=\"31.0.2\" DisplayName=\"31.0.2\" />\n    <EnumValue Name=\"31.1.0\" DisplayName=\"31.1.0\" />\n    <EnumValue Name=\"31.2.0\" DisplayName=\"31.2.0\" />\n    <EnumValue Name=\"31.2.1\" DisplayName=\"31.2.1\" />\n    <EnumValue Name=\"31.3.0\" DisplayName=\"31.3.0\" />\n    <EnumValue Name=\"31.3.1\" DisplayName=\"31.3.1\" />\n    <EnumValue Name=\"31.4.0\" DisplayName=\"31.4.0\" />\n    <EnumValue Name=\"31.5.0\" DisplayName=\"31.5.0\" />\n    <EnumValue Name=\"31.6.0\" DisplayName=\"31.6.0\" />\n    <EnumValue Name=\"31.7.0\" DisplayName=\"31.7.0\" />\n    <EnumValue Name=\"31.7.1\" DisplayName=\"31.7.1\" />\n    <EnumValue Name=\"31.7.2\" DisplayName=\"31.7.2\" />\n    <EnumValue Name=\"31.7.3\" DisplayName=\"31.7.3\" />\n    <EnumValue Name=\"31.7.4\" DisplayName=\"31.7.4\" />\n    <EnumValue Name=\"31.7.5\" DisplayName=\"31.7.5\" />\n    <EnumValue Name=\"31.7.6\" DisplayName=\"31.7.6\" />\n    <EnumValue Name=\"31.7.7\" DisplayName=\"31.7.7\" />\n    <EnumValue Name=\"32.0.0\" DisplayName=\"32.0.0\" />\n    <EnumValue Name=\"32.0.1\" DisplayName=\"32.0.1\" />\n    <EnumValue Name=\"32.0.2\" DisplayName=\"32.0.2\" />\n    <EnumValue Name=\"32.1.0\" DisplayName=\"32.1.0\" />\n    <EnumValue Name=\"32.1.1\" DisplayName=\"32.1.1\" />\n    <EnumValue Name=\"32.1.2\" DisplayName=\"32.1.2\" />\n    <EnumValue Name=\"32.2.0\" DisplayName=\"32.2.0\" />\n    <EnumValue Name=\"32.2.1\" DisplayName=\"32.2.1\" />\n    <EnumValue Name=\"32.2.2\" DisplayName=\"32.2.2\" />\n    <EnumValue Name=\"32.2.3\" DisplayName=\"32.2.3\" />\n    <EnumValue Name=\"32.2.4\" DisplayName=\"32.2.4\" />\n    <EnumValue Name=\"32.2.5\" DisplayName=\"32.2.5\" />\n    <EnumValue Name=\"32.2.6\" DisplayName=\"32.2.6\" />\n    <EnumValue Name=\"32.2.7\" DisplayName=\"32.2.7\" />\n    <EnumValue Name=\"32.2.8\" DisplayName=\"32.2.8\" />\n    <EnumValue Name=\"32.3.0\" DisplayName=\"32.3.0\" />\n    <EnumValue Name=\"32.3.1\" DisplayName=\"32.3.1\" />\n    <EnumValue Name=\"32.3.2\" DisplayName=\"32.3.2\" />\n    <EnumValue Name=\"32.3.3\" DisplayName=\"32.3.3\" />\n    <EnumValue Name=\"33.0.0\" DisplayName=\"33.0.0\" />\n    <EnumValue Name=\"33.0.1\" DisplayName=\"33.0.1\" />\n    <EnumValue Name=\"33.0.2\" DisplayName=\"33.0.2\" />\n    <EnumValue Name=\"33.1.0\" DisplayName=\"33.1.0\" />\n    <EnumValue Name=\"33.2.0\" DisplayName=\"33.2.0\" />\n    <EnumValue Name=\"33.2.1\" DisplayName=\"33.2.1\" />\n    <EnumValue Name=\"33.3.0\" DisplayName=\"33.3.0\" />\n    <EnumValue Name=\"33.3.1\" DisplayName=\"33.3.1\" />\n    <EnumValue Name=\"33.3.2\" DisplayName=\"33.3.2\" />\n    <EnumValue Name=\"33.4.0\" DisplayName=\"33.4.0\" />\n    <EnumValue Name=\"33.4.1\" DisplayName=\"33.4.1\" />\n    <EnumValue Name=\"33.4.2\" DisplayName=\"33.4.2\" />\n    <EnumValue Name=\"33.4.3\" DisplayName=\"33.4.3\" />\n    <EnumValue Name=\"33.4.4\" DisplayName=\"33.4.4\" />\n    <EnumValue Name=\"33.4.5\" DisplayName=\"33.4.5\" />\n    <EnumValue Name=\"33.4.6\" DisplayName=\"33.4.6\" />\n    <EnumValue Name=\"33.4.7\" DisplayName=\"33.4.7\" />\n    <EnumValue Name=\"33.4.8\" DisplayName=\"33.4.8\" />\n    <EnumValue Name=\"33.4.9\" DisplayName=\"33.4.9\" />\n    <EnumValue Name=\"33.4.10\" DisplayName=\"33.4.10\" />\n    <EnumValue Name=\"33.4.11\" DisplayName=\"33.4.11\" />\n    <EnumValue Name=\"34.0.0\" DisplayName=\"34.0.0\" />\n    <EnumValue Name=\"34.0.1\" DisplayName=\"34.0.1\" />\n    <EnumValue Name=\"34.0.2\" DisplayName=\"34.0.2\" />\n    <EnumValue Name=\"34.1.0\" DisplayName=\"34.1.0\" />\n    <EnumValue Name=\"34.1.1\" DisplayName=\"34.1.1\" />\n    <EnumValue Name=\"34.2.0\" DisplayName=\"34.2.0\" />\n    <EnumValue Name=\"34.3.0\" DisplayName=\"34.3.0\" />\n    <EnumValue Name=\"34.3.1\" DisplayName=\"34.3.1\" />\n    <EnumValue Name=\"34.3.2\" DisplayName=\"34.3.2\" />\n    <EnumValue Name=\"34.3.3\" DisplayName=\"34.3.3\" />\n    <EnumValue Name=\"34.3.4\" DisplayName=\"34.3.4\" />\n    <EnumValue Name=\"34.4.0\" DisplayName=\"34.4.0\" />\n    <EnumValue Name=\"34.4.1\" DisplayName=\"34.4.1\" />\n    <EnumValue Name=\"34.5.0\" DisplayName=\"34.5.0\" />\n    <EnumValue Name=\"34.5.1\" DisplayName=\"34.5.1\" />\n    <EnumValue Name=\"34.5.2\" DisplayName=\"34.5.2\" />\n    <EnumValue Name=\"34.5.3\" DisplayName=\"34.5.3\" />\n    <EnumValue Name=\"34.5.4\" DisplayName=\"34.5.4\" />\n    <EnumValue Name=\"34.5.5\" DisplayName=\"34.5.5\" />\n    <EnumValue Name=\"34.5.6\" DisplayName=\"34.5.6\" />\n    <EnumValue Name=\"34.5.7\" DisplayName=\"34.5.7\" />\n    <EnumValue Name=\"34.5.8\" DisplayName=\"34.5.8\" />\n    <EnumValue Name=\"35.0.0\" DisplayName=\"35.0.0\" />\n    <EnumValue Name=\"35.0.1\" DisplayName=\"35.0.1\" />\n    <EnumValue Name=\"35.0.2\" DisplayName=\"35.0.2\" />\n    <EnumValue Name=\"35.0.3\" DisplayName=\"35.0.3\" />\n    <EnumValue Name=\"35.1.0\" DisplayName=\"35.1.0\" />\n    <EnumValue Name=\"35.1.1\" DisplayName=\"35.1.1\" />\n    <EnumValue Name=\"35.1.2\" DisplayName=\"35.1.2\" />\n    <EnumValue Name=\"35.1.3\" DisplayName=\"35.1.3\" />\n    <EnumValue Name=\"35.1.4\" DisplayName=\"35.1.4\" />\n    <EnumValue Name=\"35.1.5\" DisplayName=\"35.1.5\" />\n    <EnumValue Name=\"35.2.0\" DisplayName=\"35.2.0\" />\n    <EnumValue Name=\"35.2.1\" DisplayName=\"35.2.1\" />\n    <EnumValue Name=\"35.2.2\" DisplayName=\"35.2.2\" />\n    <EnumValue Name=\"35.3.0\" DisplayName=\"35.3.0\" />\n    <EnumValue Name=\"35.4.0\" DisplayName=\"35.4.0\" />\n    <EnumValue Name=\"35.5.0\" DisplayName=\"35.5.0\" />\n    <EnumValue Name=\"35.5.1\" DisplayName=\"35.5.1\" />\n    <EnumValue Name=\"35.6.0\" DisplayName=\"35.6.0\" />\n    <EnumValue Name=\"35.7.0\" DisplayName=\"35.7.0\" />\n    <EnumValue Name=\"35.7.1\" DisplayName=\"35.7.1\" />\n    <EnumValue Name=\"35.7.2\" DisplayName=\"35.7.2\" />\n    <EnumValue Name=\"35.7.4\" DisplayName=\"35.7.4\" />\n    <EnumValue Name=\"35.7.5\" DisplayName=\"35.7.5\" />\n    <EnumValue Name=\"36.0.0\" DisplayName=\"36.0.0\" />\n    <EnumValue Name=\"36.0.1\" DisplayName=\"36.0.1\" />\n    <EnumValue Name=\"36.1.0\" DisplayName=\"36.1.0\" />\n    <EnumValue Name=\"36.2.0\" DisplayName=\"36.2.0\" />\n    <EnumValue Name=\"36.2.1\" DisplayName=\"36.2.1\" />\n    <EnumValue Name=\"36.3.0\" DisplayName=\"36.3.0\" />\n    <EnumValue Name=\"36.3.1\" DisplayName=\"36.3.1\" />\n    <EnumValue Name=\"36.3.2\" DisplayName=\"36.3.2\" />\n    <EnumValue Name=\"36.4.0\" DisplayName=\"36.4.0\" />\n    <EnumValue Name=\"36.5.0\" DisplayName=\"36.5.0\" />\n    <EnumValue Name=\"36.6.0\" DisplayName=\"36.6.0\" />\n    <EnumValue Name=\"36.7.0\" DisplayName=\"36.7.0\" />\n    <EnumValue Name=\"36.7.1\" DisplayName=\"36.7.1\" />\n    <EnumValue Name=\"36.7.3\" DisplayName=\"36.7.3\" />\n    <EnumValue Name=\"36.7.4\" DisplayName=\"36.7.4\" />\n    <EnumValue Name=\"36.8.0\" DisplayName=\"36.8.0\" />\n    <EnumValue Name=\"36.8.1\" DisplayName=\"36.8.1\" />\n    <EnumValue Name=\"36.9.0\" DisplayName=\"36.9.0\" />\n    <EnumValue Name=\"36.9.1\" DisplayName=\"36.9.1\" />\n    <EnumValue Name=\"36.9.2\" DisplayName=\"36.9.2\" />\n    <EnumValue Name=\"36.9.3\" DisplayName=\"36.9.3\" />\n    <EnumValue Name=\"36.9.4\" DisplayName=\"36.9.4\" />\n    <EnumValue Name=\"37.0.0\" DisplayName=\"37.0.0\" />\n    <EnumValue Name=\"37.1.0\" DisplayName=\"37.1.0\" />\n    <EnumValue Name=\"37.2.0\" DisplayName=\"37.2.0\" />\n    <EnumValue Name=\"37.2.1\" DisplayName=\"37.2.1\" />\n    <EnumValue Name=\"37.2.2\" DisplayName=\"37.2.2\" />\n    <EnumValue Name=\"37.2.3\" DisplayName=\"37.2.3\" />\n    <EnumValue Name=\"37.2.4\" DisplayName=\"37.2.4\" />\n    <EnumValue Name=\"37.2.5\" DisplayName=\"37.2.5\" />\n    <EnumValue Name=\"37.2.6\" DisplayName=\"37.2.6\" />\n    <EnumValue Name=\"37.3.0\" DisplayName=\"37.3.0\" />\n    <EnumValue Name=\"37.3.1\" DisplayName=\"37.3.1\" />\n    <EnumValue Name=\"37.4.0\" DisplayName=\"37.4.0\" />\n    <EnumValue Name=\"37.5.0\" DisplayName=\"37.5.0\" />\n    <EnumValue Name=\"37.5.1\" DisplayName=\"37.5.1\" />\n    <EnumValue Name=\"37.6.0\" DisplayName=\"37.6.0\" />\n    <EnumValue Name=\"37.6.1\" DisplayName=\"37.6.1\" />\n    <EnumValue Name=\"38.0.0\" DisplayName=\"38.0.0\" />\n    <EnumValue Name=\"38.1.0\" DisplayName=\"38.1.0\" />\n    <EnumValue Name=\"38.1.1\" DisplayName=\"38.1.1\" />\n    <EnumValue Name=\"38.1.2\" DisplayName=\"38.1.2\" />\n    <EnumValue Name=\"38.2.0\" DisplayName=\"38.2.0\" />\n    <EnumValue Name=\"38.2.1\" DisplayName=\"38.2.1\" />\n    <EnumValue Name=\"38.2.2\" DisplayName=\"38.2.2\" />\n  </EnumProperty>\n\n  <EnumProperty Name=\"ElectronBuilderVersion\"\n                DisplayName=\"Electron Builder Version\"\n                Description=\"The version of electron-builder to use (major.minor only)\"\n                Category=\"General\">\n      <!-- Consolidated to major.minor versions only -->\n      <EnumValue Name=\"22.3\" DisplayName=\"22.3\" />\n      <EnumValue Name=\"22.4\" DisplayName=\"22.4\" />\n      <EnumValue Name=\"22.5\" DisplayName=\"22.5\" />\n      <EnumValue Name=\"22.6\" DisplayName=\"22.6\" />\n      <EnumValue Name=\"22.7\" DisplayName=\"22.7\" />\n      <EnumValue Name=\"22.8\" DisplayName=\"22.8\" />\n      <EnumValue Name=\"22.9\" DisplayName=\"22.9\" />\n      <EnumValue Name=\"22.10\" DisplayName=\"22.10\" />\n      <EnumValue Name=\"22.11\" DisplayName=\"22.11\" />\n      <EnumValue Name=\"22.12\" DisplayName=\"22.12\" />\n      <EnumValue Name=\"22.13\" DisplayName=\"22.13\" />\n      <EnumValue Name=\"22.14\" DisplayName=\"22.14\" />\n      <EnumValue Name=\"23.0\" DisplayName=\"23.0\" />\n      <EnumValue Name=\"23.1\" DisplayName=\"23.1\" />\n      <EnumValue Name=\"23.2\" DisplayName=\"23.2\" />\n      <EnumValue Name=\"23.3\" DisplayName=\"23.3\" />\n      <EnumValue Name=\"23.4\" DisplayName=\"23.4\" />\n      <EnumValue Name=\"23.5\" DisplayName=\"23.5\" />\n      <EnumValue Name=\"23.6\" DisplayName=\"23.6\" />\n      <EnumValue Name=\"24.1\" DisplayName=\"24.1\" />\n      <EnumValue Name=\"24.2\" DisplayName=\"24.2\" />\n      <EnumValue Name=\"24.3\" DisplayName=\"24.3\" />\n      <EnumValue Name=\"24.4\" DisplayName=\"24.4\" />\n      <EnumValue Name=\"24.5\" DisplayName=\"24.5\" />\n      <EnumValue Name=\"24.6\" DisplayName=\"24.6\" />\n      <EnumValue Name=\"24.7\" DisplayName=\"24.7\" />\n      <EnumValue Name=\"24.8\" DisplayName=\"24.8\" />\n      <EnumValue Name=\"24.9\" DisplayName=\"24.9\" />\n      <EnumValue Name=\"24.10\" DisplayName=\"24.10\" />\n      <EnumValue Name=\"24.11\" DisplayName=\"24.11\" />\n      <EnumValue Name=\"24.12\" DisplayName=\"24.12\" />\n      <EnumValue Name=\"24.13\" DisplayName=\"24.13\" />\n      <EnumValue Name=\"26.0\" DisplayName=\"26.0\" />\n      <EnumValue Name=\"27\" DisplayName=\"27\" />\n      <EnumValue Name=\"28\" DisplayName=\"28\" />\n      <EnumValue Name=\"29\" DisplayName=\"29\" />\n      <EnumValue Name=\"30\" DisplayName=\"30\" />\n  </EnumProperty>\n\n  <EnumProperty Name=\"RuntimeIdentifier\"\n                DisplayName=\"Target Runtime Identifier (RID)\"\n                Description=\"The target platform to build for\"\n                Category=\"General\">\n      <EnumValue Name=\"win-x64\" DisplayName=\"win-x64\" />\n      <EnumValue Name=\"win-x86\" DisplayName=\"win-x86\" />\n      <EnumValue Name=\"win-arm64\" DisplayName=\"win-arm64\" />\n      <EnumValue Name=\"linux-x64\" DisplayName=\"linux-x64\" />\n      <EnumValue Name=\"linux-arm\" DisplayName=\"linux-arm\" />\n      <EnumValue Name=\"linux-arm64\" DisplayName=\"linux-arm64\" />\n      <EnumValue Name=\"osx-x64\" DisplayName=\"osx-x64\" />\n      <EnumValue Name=\"osx-arm64\" DisplayName=\"osx-arm64\" />\n  </EnumProperty>\n\n  <BoolProperty Name=\"ElectronSingleInstance\"\n                DisplayName=\"Single Instance Application\"\n                Description=\"If enabled, only one instance of the application will run at a time\"\n                Category=\"General\">\n  </BoolProperty>\n\n  <StringProperty Name=\"ElectronBuilderJson\"\n                  DisplayName=\"Electron Builder Configuration File\"\n                  Description=\"Must be located in the .\\Properties folder of the project. Default: electron-builder.json\"\n                  Category=\"General\">\n  </StringProperty>\n\n  <StringProperty Name=\"ElectronSplashScreen\"\n                  DisplayName=\"Splash Screen Image\"\n                  Description=\"Choose a PNG image to be shown as splash screen on startup\"\n                  Subtype=\"File\"\n                  Category=\"General\">\n      <StringProperty.DataSource>\n          <DataSource Persistence=\"ProjectFileWithInterception\" HasConfigurationCondition=\"False\" />\n      </StringProperty.DataSource>\n      <StringProperty.ValueEditors>\n          <ValueEditor EditorType=\"FilePath\">\n              <ValueEditor.Metadata>\n                  <NameValuePair Name=\"FileTypeFilter\" Value=\"Image files (*.png,*.jpg,*.jpeg)|*.png;*.jpg;*.jpeg|All files (*.*)|*.*\" />\n              </ValueEditor.Metadata>\n          </ValueEditor>\n      </StringProperty.ValueEditors>\n  </StringProperty>\n\n  <StringProperty Name=\"ElectronIcon\"\n                  DisplayName=\"App Icon\"\n                  Description=\"Choose a ICO file to be used as application icon\"\n                  Subtype=\"File\"\n                  Category=\"General\">\n      <StringProperty.DataSource>\n          <DataSource Persistence=\"ProjectFileWithInterception\" HasConfigurationCondition=\"False\" />\n      </StringProperty.DataSource>\n      <StringProperty.ValueEditors>\n          <ValueEditor EditorType=\"FilePath\">\n              <ValueEditor.Metadata>\n                  <NameValuePair Name=\"FileTypeFilter\" Value=\"Icon files (*.ico)|*.ico|All files (*.*)|*.*\" />\n              </ValueEditor.Metadata>\n          </ValueEditor>\n      </StringProperty.ValueEditors>\n  </StringProperty>\n\n  <!--AppInfo Category -->\n\n  <StringProperty Name=\"Title\"\n                  DisplayName=\"Title\"\n                  Description=\"The title of the application\"\n                  Category=\"AppInfo\" />\n\n  <StringProperty Name=\"Version\"\n                  DisplayName=\"App Version\"\n                  Description=\"The version of the app, following the major.minor.patch pattern. Version numbers may include a pre-release suffix.\"\n                  Category=\"AppInfo\" />\n\n  <StringProperty Name=\"ElectronPackageId\"\n                  DisplayName=\"App Identifier\"\n                  Category=\"AppInfo\">\n  </StringProperty>\n\n  <StringProperty Name=\"Description\"\n                  DisplayName=\"App Description\"\n                  Description=\"A description of the app for UI display.\"\n                  Category=\"AppInfo\">\n      <StringProperty.ValueEditors>\n          <ValueEditor EditorType=\"MultiLineString\" />\n      </StringProperty.ValueEditors>\n  </StringProperty>\n\n  <StringProperty Name=\"Company\"\n                  DisplayName=\"Company\"\n                  Category=\"AppInfo\">\n  </StringProperty>\n\n  <StringProperty Name=\"License\"\n                  DisplayName=\"License\"\n                  Category=\"AppInfo\">\n  </StringProperty>\n\n  <StringProperty Name=\"ProjectUrl\"\n                  DisplayName=\"Project Url\"\n                  Category=\"AppInfo\">\n  </StringProperty>\n\n  <StringProperty Name=\"Copyright\"\n                  DisplayName=\"Copyright\"\n                  Description=\"Copyright details for the app.\"\n                  Category=\"AppInfo\" />\n\n  <StringProperty Name=\"PackageTags\"\n                  DisplayName=\"Keywords\"\n                  Description=\"A semicolon-delimited list of tags and keywords that describe the application\"\n                  Category=\"AppInfo\" />\n\n\n\n\n  <!--<StringProperty Name=\"_AcsClickOnceNote\"\n                  DisplayName=\"Ignored\"\n                  Description=\"IMPORTANT: Enabling ClickOnce signing disables the regular signing during the build.\n                  ClickOnce signing is performed when publishing instead but will also sign the project executable.\"\n                  Category=\"General\">\n    <StringProperty.DataSource>\n      <DataSource PersistedName=\"_AcsClickOnceNote\" Persistence=\"UserFile\" HasConfigurationCondition=\"False\" />\n    </StringProperty.DataSource>\n    <StringProperty.ValueEditors>\n      <ValueEditor EditorType=\"Description\" />\n    </StringProperty.ValueEditors>\n  </StringProperty>\n\n\n\n  <StringProperty Name=\"_AcsCiAuthNote\"\n                  DisplayName=\"Ignored\"\n                  Description=\"ERROR: Currently, ClickOnce signing and MSIX signing does not work with an access token.  \n                  EnvironmentCredential must be used in these cases.\"\n                  Category=\"Auxiliary\">\n    <StringProperty.DataSource>\n      <DataSource PersistedName=\"_AcsClickOnceNote\" Persistence=\"UserFile\" HasConfigurationCondition=\"False\" />\n    </StringProperty.DataSource>\n    <StringProperty.ValueEditors>\n      <ValueEditor EditorType=\"Description\" />\n    </StringProperty.ValueEditors>\n  </StringProperty>\n\n  <StringProperty Name=\"AcsAdditionalFiles\"\n                  DisplayName=\"Sign Additional Files\"\n                  Description=\"Enter file paths relative to the output folder\"\n                  Category=\"Auxiliary\">\n    <StringProperty.ValueEditors>\n      <ValueEditor EditorType=\"MultiLineString\">\n        <ValueEditor.Metadata>\n          <NameValuePair Name=\"UseMonospaceFont\" Value=\"True\" />\n        </ValueEditor.Metadata>\n      </ValueEditor>\n    </StringProperty.ValueEditors>\n  </StringProperty>-->\n\n\n</Rule>\n"
  },
  {
    "path": "src/ElectronNET/build/ElectronNETRules.Project2.xaml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Rule Name=\"Build\" \n      DisplayName=\"Build\" \n      OverrideMode=\"Extend\"\n      Order=\"300\" \n      PageTemplate=\"generic\" \n      xmlns=\"http://schemas.microsoft.com/build/2009/properties\">\n\n    <Rule.Categories>\n        <Category Name=\"General\"\n                  DisplayName=\"General\" />\n\n        <Category Name=\"ErrorsAndWarnings\"\n                  Description=\"Configures the error and warning options for the build process.\"\n                  DisplayName=\"Errors and warnings\" />\n\n        <Category Name=\"Output\"\n                  Description=\"Configures the output options for the build process.\"\n                  DisplayName=\"Output\" />\n\n        <Category Name=\"Events\"\n                  Description=\"Configures custom events that run before and after build.\"\n                  DisplayName=\"Events\" />\n\n        <Category Name=\"Publish\"\n                  DisplayName=\"Publish\"\n                  Description=\"Configures options in the publish process.\" />\n    \n        <Category Name=\"StrongNaming\"\n                  Description=\"Configures strong name signing of build outputs.\"\n                  DisplayName=\"Strong naming\" />\n\n        <Category Name=\"Advanced\"\n                  DisplayName=\"Advanced\"\n                  Description=\"Advanced settings for the application.\" />\n    </Rule.Categories>\n\n  <Rule.DataSource>\n    <DataSource Persistence=\"ProjectFile\" Label=\"ElectronNetCommon\" HasConfigurationCondition=\"False\" />\n  </Rule.DataSource>\n\n  <!--General Category -->\n\n  <DynamicEnumProperty Name=\"PlatformTarget\"  Visible=\"False\"\n                       DisplayName=\"Platform target\"\n                       Description=\"Specifies the processor to be targeted by the output file. Choose 'Any CPU' to specify that any processor is acceptable, allowing the application to run on the broadest range of hardware.\"\n                       HelpUrl=\"https://go.microsoft.com/fwlink/?linkid=2147129\"\n                       Category=\"General\"\n                       EnumProvider=\"PlatformTargetEnumProvider\"\n                       MultipleValuesAllowed=\"False\">\n  </DynamicEnumProperty>\n\n\n  <StringProperty Name=\"BaseOutputPath\"  Visible=\"False\"\n                  DisplayName=\"Base output path\"\n                  Description=\"Specifies the base location for the project's output during build. Subfolders will be appended to this path to differentiate project configuration.\"\n                  Category=\"Output\"\n                  Subtype=\"directory\">\n  </StringProperty>\n\n \n</Rule>\n"
  },
  {
    "path": "src/ElectronNET/build/electron-builder.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/electron-userland/electron-builder/refs/heads/master/packages/app-builder-lib/scheme.json\",\n  \"compression\": \"maximum\",\n  \"linux\": {\n    \"target\": [\n      \"tar.xz\"\n    ],\n    \"executableArgs\": [ \"--no-sandbox\" ],\n    \"artifactName\": \"${name}-${arch}-${version}.${ext}\"\n  },\n  \"win\": {\n    \"target\": [\n      {\n        \"target\": \"portable\",\n        \"arch\": \"x64\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "src/ElectronNET/build/package.template.json",
    "content": "{\n  \"name\": \"$(ElectronPackageId)\",\n  \"productName\": \"$(ElectronTitle)\",\n  \"build\": {\n    \"appId\": \"$(ElectronPackageId)\",\n    \"linux\": {\n      \"desktop\": {\n        \"entry\": { \"Name\": \"$(Title)\" }\n      },\n      \"executableName\": \"$(ElectronPackageId)\"\n    },\n    \"deb\": {\n      \"desktop\": {\n        \"entry\": { \"Name\": \"$(Title)\" }\n      }\n    }\n  },\n  \"description\": \"$(Description)\",\n  \"version\": \"$(Version)\",\n  \"main\": \"main.js\",\n  \"author\": {\n    \"name\": \"$(Company)\"\n  },\n  \"license\": \"$(License)\",\n  \"executable\": \"$(TargetName)\",\n  \"singleInstance\": $(ElectronSingleInstance),\n  \"homepage\": \"$(ProjectUrl)\",\n  \"splashscreen\": {\n    \"imageFile\": \"$(ElectronSplashScreen)\"\n  },\n  \"scripts\": {\n    \"start\": \"tsc -p .\"\n  },\n  \"dependencies\": {\n    \"dasherize\": \"^2.0.0\",\n    \"electron-updater\": \"^6.6.2\",\n    \"image-size\": \"^1.2.1\",\n    \"portscanner\": \"^2.2.0\",\n    \"socket.io\": \"^4.8.1\",\n    \"electron-host-hook\": \"file:./ElectronHostHook\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.18\",\n    \"electron\": \"$(ElectronVersion)\",\n    \"eslint\": \"^9.37.0\",\n    \"typescript\": \"^5.9.3\"\n  }\n}"
  },
  {
    "path": "src/ElectronNET/build/update_electron_versions.py",
    "content": "#!/usr/bin/env python3\n\"\"\"\nUpdate Electron version list in ElectronNETRules.Project.xaml\n\nThis script:\n1. Downloads the Electron releases feed from GitHub\n2. Filters for stable releases >= 23.0.0\n3. Generates the ElectronVersion enum XML\n4. Updates the XAML file with the new version list\n\"\"\"\n\nimport json\nimport re\nimport urllib.request\nfrom pathlib import Path\n\n\ndef download_releases():\n    \"\"\"Download Electron releases JSON from GitHub.\"\"\"\n    url = \"https://releases.electronjs.org/releases.json\"\n    print(f\"Downloading releases from {url}...\")\n    \n    with urllib.request.urlopen(url) as response:\n        data = response.read()\n    \n    print(f\"Downloaded {len(data)} bytes\")\n    return json.loads(data)\n\n\ndef filter_versions(releases, min_version=\"23.0.0\"):\n    \"\"\"Filter and sort stable Electron versions.\"\"\"\n    print(f\"Filtering versions >= {min_version}...\")\n    \n    # Regular expression for stable versions (major.minor.patch)\n    stable_pattern = re.compile(r'^\\d+\\.\\d+\\.\\d+$')\n    \n    # Parse minimum version\n    min_parts = tuple(map(int, min_version.split('.')))\n    \n    # Filter and collect versions\n    versions = set()\n    for release in releases:\n        version = release.get('version', '')\n        if stable_pattern.match(version):\n            parts = tuple(map(int, version.split('.')))\n            if parts >= min_parts:\n                versions.add(version)\n    \n    # Sort versions\n    sorted_versions = sorted(versions, key=lambda v: tuple(map(int, v.split('.'))))\n    \n    print(f\"Found {len(sorted_versions)} stable versions\")\n    return sorted_versions\n\n\ndef generate_enum_xml(versions):\n    \"\"\"Generate the ElectronVersion enum property XML.\"\"\"\n    lines = [\n        '  <EnumProperty Name=\"ElectronVersion\"',\n        '                DisplayName=\"Electron Version\"',\n        '                Description=\"The version of Electron to use for building (full semver)\"',\n        '                Category=\"General\">',\n        '    <!-- Auto-generated list of stable Electron releases -->',\n    ]\n    \n    for version in versions:\n        lines.append(f'    <EnumValue Name=\"{version}\" DisplayName=\"{version}\" />')\n    \n    lines.append('  </EnumProperty>')\n    \n    return '\\n'.join(lines)\n\n\ndef update_xaml_file(xaml_path, enum_xml):\n    \"\"\"Update the XAML file with the new enum.\"\"\"\n    print(f\"Updating {xaml_path}...\")\n    \n    # Read the original file\n    content = Path(xaml_path).read_text(encoding='utf-8')\n    \n    # Find the ElectronVersion enum markers\n    start_marker = '  <EnumProperty Name=\"ElectronVersion\"'\n    end_marker = '  </EnumProperty>'\n    \n    start_idx = content.find(start_marker)\n    if start_idx == -1:\n        raise ValueError(\"Could not find ElectronVersion EnumProperty start marker\")\n    \n    end_idx = content.find(end_marker, start_idx)\n    if end_idx == -1:\n        raise ValueError(\"Could not find ElectronVersion EnumProperty end marker\")\n    \n    end_idx += len(end_marker)\n    \n    # Replace the enum section\n    new_content = content[:start_idx] + enum_xml + '\\n' + content[end_idx:]\n    \n    # Write the updated file\n    Path(xaml_path).write_text(new_content, encoding='utf-8')\n    \n    print(\"Successfully updated XAML file\")\n\n\ndef main():\n    \"\"\"Main entry point.\"\"\"\n    try:\n        # Paths\n        xaml_file = \"build/ElectronNETRules.Project.xaml\"\n        \n        # Download and process releases\n        releases = download_releases()\n        versions = filter_versions(releases, min_version=\"23.0.0\")\n        \n        # Generate enum XML\n        enum_xml = generate_enum_xml(versions)\n        \n        # Update XAML file\n        update_xaml_file(xaml_file, enum_xml)\n        \n        print(f\"\\n✓ Successfully updated {xaml_file} with {len(versions)} Electron versions\")\n        print(f\"  Version range: {versions[0]} to {versions[-1]}\")\n        \n    except Exception as e:\n        print(f\"\\n✗ Error: {e}\")\n        return 1\n    \n    return 0\n\n\nif __name__ == \"__main__\":\n    exit(main())\n"
  },
  {
    "path": "src/ElectronNET.API/API/ApiBase.cs",
    "content": "﻿// ReSharper disable InconsistentNaming\n\nnamespace ElectronNET.API\n{\n    using Common;\n    using System.Diagnostics.CodeAnalysis;\n    using System.Globalization;\n    using System;\n    using System.Collections.Concurrent;\n    using System.Diagnostics;\n    using System.Runtime.CompilerServices;\n    using System.Threading.Tasks;\n\n    public abstract class ApiBase\n    {\n        protected enum SocketTaskEventNameTypes\n        {\n            DashesLowerFirst,\n            NoDashUpperFirst\n        }\n\n        protected enum SocketTaskMessageNameTypes\n        {\n            DashesLowerFirst,\n            NoDashUpperFirst\n        }\n\n        protected enum SocketEventNameTypes\n        {\n            DashedLower,\n            CamelCase,\n        }\n\n        private static readonly TimeSpan InvocationTimeout = 1000.ms();\n\n        private readonly string objectName;\n        private readonly ConcurrentDictionary<string, Invocator> invocators;\n        private readonly ConcurrentDictionary<string, string> invocationEventNames = new();\n        private readonly ConcurrentDictionary<string, string> invocationMessageNames = new();\n        private readonly ConcurrentDictionary<string, string> methodMessageNames = new();\n        private static readonly ConcurrentDictionary<string, EventContainer> eventContainers = new();\n        private static readonly ConcurrentDictionary<string, ConcurrentDictionary<string, Invocator>> AllInvocators = new();\n\n        private readonly object objLock = new object();\n\n        public virtual int Id\n        {\n            get => -1;\n\n            // ReSharper disable once ValueParameterNotUsed\n            protected set\n            {\n            }\n        }\n\n        protected abstract SocketTaskEventNameTypes SocketTaskEventNameType { get; }\n        protected virtual SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.NoDashUpperFirst;\n        protected virtual SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;\n\n        protected ApiBase()\n        {\n            this.objectName = this.GetType().Name.LowerFirst();\n            this.invocators = AllInvocators.GetOrAdd(this.objectName, _ => new ConcurrentDictionary<string, Invocator>());\n        }\n\n        protected void CallMethod0([CallerMemberName] string callerName = null)\n        {\n            var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);\n            if (this.Id >= 0)\n            {\n                BridgeConnector.Socket.Emit(messageName, this.Id);\n            }\n            else\n            {\n                BridgeConnector.Socket.Emit(messageName);\n            }\n        }\n\n        protected void CallMethod1(object val1, [CallerMemberName] string callerName = null)\n        {\n            var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);\n            if (this.Id >= 0)\n            {\n                BridgeConnector.Socket.Emit(messageName, this.Id, val1);\n            }\n            else\n            {\n                BridgeConnector.Socket.Emit(messageName, val1);\n            }\n        }\n\n        protected void CallMethod2(object val1, object val2, [CallerMemberName] string callerName = null)\n        {\n            var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);\n            if (this.Id >= 0)\n            {\n                BridgeConnector.Socket.Emit(messageName, this.Id, val1, val2);\n            }\n            else\n            {\n                BridgeConnector.Socket.Emit(messageName, val1, val2);\n            }\n        }\n\n        protected void CallMethod3(object val1, object val2, object val3, [CallerMemberName] string callerName = null)\n        {\n            var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);\n            if (this.Id >= 0)\n            {\n                BridgeConnector.Socket.Emit(messageName, this.Id, val1, val2, val3);\n            }\n            else\n            {\n                BridgeConnector.Socket.Emit(messageName, val1, val2, val3);\n            }\n        }\n\n        protected Task<T> InvokeAsync<T>(object arg = null, [CallerMemberName] string callerName = null)\n        {\n            return this.InvokeAsyncWithTimeout<T>(InvocationTimeout, arg, callerName);\n        }\n\n        protected Task<T> InvokeAsyncWithTimeout<T>(TimeSpan invocationTimeout, object arg = null, [CallerMemberName] string callerName = null)\n        {\n            Debug.Assert(callerName != null, nameof(callerName) + \" != null\");\n\n            lock (this.objLock)\n            {\n                return this.invocators.GetOrAdd(callerName, _ =>\n                {\n                    var getter = new Invocator<T>(this, callerName, invocationTimeout, arg);\n\n                    getter.Task<T>().ContinueWith(_ =>\n                    {\n                        lock (this.objLock)\n                        {\n                            return this.invocators.TryRemove(callerName, out var _);\n                        }\n                    });\n\n                    return getter;\n                }).Task<T>();\n            }\n        }\n\n        protected void AddEvent(Action value, int? id = null, [CallerMemberName] string callerName = null)\n        {\n            Debug.Assert(callerName != null, nameof(callerName) + \" != null\");\n            var eventName = this.EventName(callerName);\n\n            var eventKey = this.EventKey(eventName, id);\n\n            lock (this.objLock)\n            {\n                var container = eventContainers.GetOrAdd(eventKey, _ =>\n                {\n                    var container = new EventContainer();\n                    BridgeConnector.Socket.On(eventKey, container.OnEventAction);\n                    BridgeConnector.Socket.Emit($\"register-{eventName}\", id);\n                    return container;\n                });\n\n                container.Register(value);\n            }\n        }\n\n        protected void RemoveEvent(Action value, int? id = null, [CallerMemberName] string callerName = null)\n        {\n            Debug.Assert(callerName != null, nameof(callerName) + \" != null\");\n            var eventName = this.EventName(callerName);\n            var eventKey = this.EventKey(eventName, id);\n\n            lock (this.objLock)\n            {\n                if (eventContainers.TryGetValue(eventKey, out var container) && !container.Unregister(value))\n                {\n                    BridgeConnector.Socket.Off(eventKey);\n                    eventContainers.TryRemove(eventKey, out _);\n                }\n            }\n        }\n\n        protected void AddEvent<T>(Action<T> value, int? id = null, [CallerMemberName] string callerName = null)\n        {\n            Debug.Assert(callerName != null, nameof(callerName) + \" != null\");\n\n            var eventName = this.EventName(callerName);\n            var eventKey = this.EventKey(eventName, id);\n\n            lock (this.objLock)\n            {\n                var container = eventContainers.GetOrAdd(eventKey, _ =>\n                {\n                    var container = new EventContainer();\n                    BridgeConnector.Socket.On<T>(eventKey, container.OnEventActionT);\n                    BridgeConnector.Socket.Emit($\"register-{eventName}\", id);\n                    return container;\n                });\n\n                container.Register(value);\n            }\n        }\n\n        protected void RemoveEvent<T>(Action<T> value, int? id = null, [CallerMemberName] string callerName = null)\n        {\n            Debug.Assert(callerName != null, nameof(callerName) + \" != null\");\n            var eventName = this.EventName(callerName);\n            var eventKey = this.EventKey(eventName, id);\n\n            lock (this.objLock)\n            {\n                if (eventContainers.TryGetValue(eventKey, out var container) && !container.Unregister(value))\n                {\n                    BridgeConnector.Socket.Off(eventKey);\n                    eventContainers.TryRemove(eventKey, out _);\n                }\n            }\n        }\n\n        private string EventName(string callerName)\n        {\n            switch (this.SocketEventNameType)\n            {\n                case SocketEventNameTypes.DashedLower:\n                    return $\"{this.objectName}-{callerName.ToDashedEventName()}\";\n                case SocketEventNameTypes.CamelCase:\n                    return $\"{this.objectName}-{callerName.ToCamelCaseEventName()}\";\n                default:\n                    throw new ArgumentOutOfRangeException();\n            }\n        }\n\n        private string EventKey(string eventName, int? id)\n        {\n            return string.Format(CultureInfo.InvariantCulture, \"{0}{1:D}\", eventName, id);\n        }\n\n        internal abstract class Invocator\n        {\n            public abstract Task<T> Task<T>();\n        }\n\n        internal class Invocator<T> : Invocator\n        {\n            private readonly Task<T> tcsTask;\n            private TaskCompletionSource<T> tcs;\n\n            public Invocator(ApiBase apiBase, string callerName, TimeSpan timeout, object arg = null)\n            {\n                this.tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);\n                this.tcsTask = this.tcs.Task;\n\n                string eventName;\n                string messageName;\n\n                switch (apiBase.SocketTaskEventNameType)\n                {\n                    case SocketTaskEventNameTypes.DashesLowerFirst:\n                        eventName = apiBase.invocationEventNames.GetOrAdd(callerName, s => $\"{apiBase.objectName}-{s.StripAsync().LowerFirst()}-completed\");\n                        break;\n                    case SocketTaskEventNameTypes.NoDashUpperFirst:\n                        eventName = apiBase.invocationEventNames.GetOrAdd(callerName, s => $\"{apiBase.objectName}{s.StripAsync()}Completed\");\n                        break;\n                    default:\n                        throw new ArgumentOutOfRangeException();\n                }\n\n                switch (apiBase.SocketTaskMessageNameType)\n                {\n                    case SocketTaskMessageNameTypes.DashesLowerFirst:\n                        messageName = apiBase.invocationMessageNames.GetOrAdd(callerName, s => $\"{apiBase.objectName}-{s.StripAsync().LowerFirst()}\");\n                        break;\n                    case SocketTaskMessageNameTypes.NoDashUpperFirst:\n                        messageName = apiBase.invocationMessageNames.GetOrAdd(callerName, s => apiBase.objectName + s.StripAsync());\n                        break;\n                    default:\n                        throw new ArgumentOutOfRangeException();\n                }\n\n                BridgeConnector.Socket.Once<T>(eventName, (result) =>\n                {\n                    lock (this)\n                    {\n                        try\n                        {\n                            var value = result;\n                            this.tcs?.SetResult(value);\n                        }\n                        catch (Exception ex)\n                        {\n                            this.tcs?.TrySetException(ex);\n                        }\n                        finally\n                        {\n                            this.tcs = null;\n                        }\n                    }\n                });\n\n                if (arg != null)\n                {\n                    _ = apiBase.Id >= 0 ? BridgeConnector.Socket.Emit(messageName, apiBase.Id, arg) : BridgeConnector.Socket.Emit(messageName, arg);\n                }\n                else\n                {\n                    _ = apiBase.Id >= 0 ? BridgeConnector.Socket.Emit(messageName, apiBase.Id) : BridgeConnector.Socket.Emit(messageName);\n                }\n\n                System.Threading.Tasks.Task.Delay(timeout).ContinueWith(_ =>\n                {\n                    if (this.tcs != null)\n                    {\n                        lock (this)\n                        {\n                            if (this.tcs != null)\n                            {\n                                var ex = new TimeoutException(\n                                    $\"No response after {(long)timeout.TotalMilliseconds}ms trying to retrieve value {apiBase.objectName}.{callerName}()\"\n                                );\n                                this.tcs.TrySetException(ex);\n                                this.tcs = null;\n                            }\n                        }\n                    }\n                });\n            }\n\n            public override Task<T1> Task<T1>()\n            {\n                return this.tcsTask as Task<T1>;\n            }\n        }\n\n        [SuppressMessage(\"ReSharper\", \"InconsistentlySynchronizedField\")]\n        private class EventContainer\n        {\n            private Action eventAction;\n            private Delegate eventActionT;\n\n            private Action<T> GetEventActionT<T>()\n            {\n                return (Action<T>)this.eventActionT;\n            }\n\n            private void SetEventActionT<T>(Action<T> actionT)\n            {\n                this.eventActionT = actionT;\n            }\n\n            public void OnEventAction() => this.eventAction?.Invoke();\n\n            public void OnEventActionT<T>(T p) => this.GetEventActionT<T>()?.Invoke(p);\n\n            public void Register(Action receiver)\n            {\n                this.eventAction += receiver;\n            }\n\n            public void Register<T>(Action<T> receiver)\n            {\n                var actionT = this.GetEventActionT<T>();\n                actionT += receiver;\n                this.SetEventActionT(actionT);\n            }\n\n            public bool Unregister(Action receiver)\n            {\n                this.eventAction -= receiver;\n                return this.eventAction != null;\n            }\n\n            public bool Unregister<T>(Action<T> receiver)\n            {\n                var actionT = this.GetEventActionT<T>();\n                actionT -= receiver;\n                this.SetEventActionT(actionT);\n\n                return actionT != null;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/App.cs",
    "content": "using ElectronNET.API.Entities;\nusing ElectronNET.API.Extensions;\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Runtime.Versioning;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\n\n// ReSharper disable InconsistentNaming\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Control your application's event lifecycle.\n    /// </summary>\n    public sealed class App : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.NoDashUpperFirst;\n        protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;\n\n        /// <summary>\n        /// Emitted when all windows have been closed.\n        /// <para/>\n        /// If you do not subscribe to this event and all windows are closed, the default behavior is to quit\n        /// the app; however, if you subscribe, you control whether the app quits or not.If the user pressed\n        /// Cmd + Q, or the developer called <see cref=\"Quit\"/>, Electron will first try to close all the windows\n        /// and then emit the <see cref=\"WillQuit\"/> event, and in this case the <see cref=\"WindowAllClosed\"/> event\n        /// would not be emitted.\n        /// </summary>\n        public event Action WindowAllClosed\n        {\n            add\n            {\n                if (_windowAllClosed == null)\n                {\n                    BridgeConnector.Socket.On(\"app-window-all-closed\" + GetHashCode(), () =>\n                    {\n                        if (!Electron.WindowManager.IsQuitOnWindowAllClosed || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n                        {\n                            _windowAllClosed();\n                        }\n                    });\n\n                    BridgeConnector.Socket.Emit(\"register-app-window-all-closed\", GetHashCode());\n                }\n\n                _windowAllClosed += value;\n            }\n            remove\n            {\n                _windowAllClosed -= value;\n\n                if (_windowAllClosed == null)\n                    BridgeConnector.Socket.Off(\"app-window-all-closed\" + GetHashCode());\n            }\n        }\n\n        private event Action _windowAllClosed;\n\n        /// <summary>\n        /// Emitted before the application starts closing its windows.\n        /// <para/>\n        /// Note: If application quit was initiated by <see cref=\"AutoUpdater.QuitAndInstall\"/> then <see cref=\"BeforeQuit\"/>\n        /// is emitted after emitting close event on all windows and closing them.\n        /// <para/>\n        /// Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout.\n        /// </summary>\n        public event Func<QuitEventArgs, Task> BeforeQuit\n        {\n            add\n            {\n                if (_beforeQuit == null)\n                {\n                    BridgeConnector.Socket.On(\"app-before-quit\" + GetHashCode(), async () =>\n                    {\n                        await this._beforeQuit(new QuitEventArgs()).ConfigureAwait(false);\n\n                        if (_preventQuit)\n                        {\n                            _preventQuit = false;\n                        }\n                        else\n                        {\n                            if (_willQuit == null && _quitting == null)\n                            {\n                                Exit();\n                            }\n                            else if (_willQuit != null)\n                            {\n                                await this._willQuit(new QuitEventArgs()).ConfigureAwait(false);\n\n                                if (_preventQuit)\n                                {\n                                    _preventQuit = false;\n                                }\n                                else\n                                {\n                                    if (_quitting == null)\n                                    {\n                                        Exit();\n                                    }\n                                    else\n                                    {\n                                        await this._quitting().ConfigureAwait(false);\n                                        Exit();\n                                    }\n                                }\n                            }\n                            else if (_quitting != null)\n                            {\n                                await this._quitting().ConfigureAwait(false);\n                                Exit();\n                            }\n                        }\n                    });\n\n                    BridgeConnector.Socket.Emit(\"register-app-before-quit\", GetHashCode());\n                }\n\n                _beforeQuit += value;\n            }\n            remove\n            {\n                _beforeQuit -= value;\n\n                if (_beforeQuit == null)\n                    BridgeConnector.Socket.Off(\"app-before-quit\" + GetHashCode());\n            }\n        }\n\n        private event Func<QuitEventArgs, Task> _beforeQuit;\n\n        /// <summary>\n        /// Emitted when all windows have been closed and the application will quit.\n        /// <para/>\n        /// See the description of the <see cref=\"WindowAllClosed\"/> event for the differences between the <see cref=\"WillQuit\"/>\n        /// and <see cref=\"WindowAllClosed\"/> events.\n        /// <para/>\n        /// Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout.\n        /// </summary>\n        public event Func<QuitEventArgs, Task> WillQuit\n        {\n            add\n            {\n                if (_willQuit == null)\n                {\n                    BridgeConnector.Socket.On(\"app-will-quit\" + GetHashCode(), async () =>\n                    {\n                        await this._willQuit(new QuitEventArgs()).ConfigureAwait(false);\n\n                        if (_preventQuit)\n                        {\n                            _preventQuit = false;\n                        }\n                        else\n                        {\n                            if (_quitting == null)\n                            {\n                                Exit();\n                            }\n                            else\n                            {\n                                await this._quitting().ConfigureAwait(false);\n                                Exit();\n                            }\n                        }\n                    });\n\n                    BridgeConnector.Socket.Emit(\"register-app-will-quit\", GetHashCode());\n                }\n\n                _willQuit += value;\n            }\n            remove\n            {\n                _willQuit -= value;\n\n                if (_willQuit == null)\n                    BridgeConnector.Socket.Off(\"app-will-quit\" + GetHashCode());\n            }\n        }\n\n        private event Func<QuitEventArgs, Task> _willQuit;\n\n        /// <summary>\n        /// Emitted when the application is quitting.\n        /// <para/>\n        /// Note: On Windows, this event will not be emitted if the app is closed due to a shutdown/restart of the system or a user logout.\n        /// </summary>\n        public event Func<Task> Quitting\n        {\n            add\n            {\n                if (_quitting == null)\n                {\n                    BridgeConnector.Socket.On(\"app-will-quit\" + GetHashCode() + \"quitting\", async () =>\n                    {\n                        if (_willQuit == null)\n                        {\n                            await this._quitting().ConfigureAwait(false);\n                            Exit();\n                        }\n                    });\n\n                    BridgeConnector.Socket.Emit(\"register-app-will-quit\", GetHashCode() + \"quitting\");\n                }\n\n                _quitting += value;\n            }\n            remove\n            {\n                _quitting -= value;\n\n                if (_quitting == null)\n                    BridgeConnector.Socket.Off(\"app-will-quit\" + GetHashCode() + \"quitting\");\n            }\n        }\n\n        private event Func<Task> _quitting;\n\n        /// <summary>\n        /// Emitted when a <see cref=\"BrowserWindow\"/> blurred.\n        /// </summary>\n        public event Action BrowserWindowBlur\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when a <see cref=\"BrowserWindow\"/> gets focused.\n        /// </summary>\n        public event Action BrowserWindowFocus\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when a new <see cref=\"BrowserWindow\"/> is created.\n        /// </summary>\n        public event Action BrowserWindowCreated\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when a new <see cref=\"WebContents\"/> is created.\n        /// </summary>\n        public event Action WebContentsCreated\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when Chrome’s accessibility support changes. This event fires when assistive technologies, such as\n        /// screen readers, are enabled or disabled. See https://www.chromium.org/developers/design-documents/accessibility for more details.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> when Chrome's accessibility support is enabled, <see langword=\"false\"/> otherwise.</returns>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action<bool> AccessibilitySupportChanged\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when the application has finished basic startup.\n        /// </summary>\n        public event Action Ready\n        {\n            add\n            {\n                if (IsReady)\n                {\n                    value();\n                }\n\n                _ready += value;\n            }\n            remove\n            {\n                _ready -= value;\n            }\n        }\n\n        private event Action _ready;\n\n        /// <summary>\n        /// Application host fully started.\n        /// </summary>\n        public bool IsReady\n        {\n            get\n            {\n                return _isReady;\n            }\n            internal set\n            {\n                _isReady = value;\n\n                if (value)\n                {\n                    _ready?.Invoke();\n                }\n            }\n        }\n\n        private bool _isReady = false;\n\n        /// <summary>\n        /// Emitted when a MacOS user wants to open a file with the application. The open-file event is usually emitted\n        /// when the application is already open and the OS wants to reuse the application to open the file.\n        /// open-file is also emitted when a file is dropped onto the dock and the application is not yet running.\n        /// <para/>\n        /// On Windows, you have to parse the arguments using App.CommandLine to get the filepath.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        public event Action<string> OpenFile\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n\n        /// <summary>\n        /// Emitted when a MacOS user wants to open a URL with the application. Your application's Info.plist file must\n        /// define the URL scheme within the CFBundleURLTypes key, and set NSPrincipalClass to AtomApplication.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        public event Action<string> OpenUrl\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// A <see cref=\"string\"/> property that indicates the current application's name, which is the name in the\n        /// application's package.json file.\n        ///\n        /// Usually the name field of package.json is a short lowercase name, according to the npm modules spec. You\n        /// should usually also specify a productName field, which is your application's full capitalized name, and\n        /// which will be preferred over name by Electron.\n        /// </summary>\n        public string Name\n        {\n            [Obsolete(\"Use the asynchronous version NameAsync instead\")]\n            get\n            {\n                return NameAsync.Result;\n            }\n            set\n            {\n                BridgeConnector.Socket.Emit(\"appSetName\", value);\n            }\n        }\n\n        /// <summary>\n        /// A <see cref=\"string\"/> property that indicates the current application's name, which is the name in the\n        /// application's package.json file.\n        ///\n        /// Usually the name field of package.json is a short lowercase name, according to the npm modules spec. You\n        /// should usually also specify a productName field, which is your application's full capitalized name, and\n        /// which will be preferred over name by Electron.\n        /// </summary>\n        public Task<string> NameAsync\n        {\n            get\n            {\n                return this.InvokeAsync<string>();\n            }\n        }\n\n\n        internal App()\n        {\n            CommandLine = new CommandLine();\n        }\n\n        internal static App Instance\n        {\n            get\n            {\n                if (_app == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_app == null)\n                        {\n                            _app = new App();\n                        }\n                    }\n                }\n\n                return _app;\n            }\n        }\n\n        private static App _app;\n        private static object _syncRoot = new object();\n\n\n        /// <summary>\n        /// Try to close all windows. The <see cref=\"BeforeQuit\"/> event will be emitted first. If all windows are successfully\n        /// closed, the <see cref=\"WillQuit\"/> event will be emitted and by default the application will terminate. This method\n        /// guarantees that all beforeunload and unload event handlers are correctly executed. It is possible\n        /// that a window cancels the quitting by returning <see langword=\"false\"/> in the beforeunload event handler.\n        /// </summary>\n        public void Quit()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// All windows will be closed immediately without asking user and the <see cref=\"BeforeQuit\"/> and <see cref=\"WillQuit\"/>\n        /// events will not be emitted.\n        /// </summary>\n        /// <param name=\"exitCode\">Exits immediately with exitCode. exitCode defaults to 0.</param>\n        public void Exit(int exitCode = 0)\n        {\n            this.CallMethod1(exitCode);\n        }\n\n        public void DisposeSocket()\n        {\n            BridgeConnector.Socket.Dispose();\n        }\n\n        /// <summary>\n        /// Relaunches the app when current instance exits. By default the new instance will use the same working directory\n        /// and command line arguments with current instance.\n        /// <para/>\n        /// Note that this method does not quit the app when executed, you have to call <see cref=\"Quit\"/> or <see cref=\"Exit\"/>\n        /// after calling <see cref=\"Relaunch()\"/> to make the app restart.\n        /// <para/>\n        /// When <see cref=\"Relaunch()\"/> is called for multiple times, multiple instances will be started after current instance\n        /// exited.\n        /// </summary>\n        public void Relaunch()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// Relaunches the app when current instance exits. By default the new instance will use the same working directory\n        /// and command line arguments with current instance. When <see cref=\"RelaunchOptions.Args\"/> is specified, the\n        /// <see cref=\"RelaunchOptions.Args\"/> will be passed as command line arguments instead. When <see cref=\"RelaunchOptions.ExecPath\"/>\n        /// is specified, the <see cref=\"RelaunchOptions.ExecPath\"/> will be executed for relaunch instead of current app.\n        /// <para/>\n        /// Note that this method does not quit the app when executed, you have to call <see cref=\"Quit\"/> or <see cref=\"Exit\"/>\n        /// after calling <see cref=\"Relaunch()\"/> to make the app restart.\n        /// <para/>\n        /// When <see cref=\"Relaunch()\"/> is called for multiple times, multiple instances will be started after current instance\n        /// exited.\n        /// </summary>\n        /// <param name=\"relaunchOptions\">Options for the relaunch.</param>\n        public void Relaunch(RelaunchOptions relaunchOptions)\n        {\n            this.CallMethod1(relaunchOptions);\n        }\n\n        /// <summary>\n        /// On Linux, focuses on the first visible window. On macOS, makes the application the active app. On Windows, focuses\n        /// on the application's first window.\n        /// </summary>\n        public void Focus()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// On Linux, focuses on the first visible window. On macOS, makes the application the active app. On Windows, focuses\n        /// on the application's first window.\n        /// <para/>\n        /// You should seek to use the <see cref=\"FocusOptions.Steal\"/> option as sparingly as possible.\n        /// </summary>\n        public void Focus(FocusOptions focusOptions)\n        {\n            this.CallMethod1(focusOptions);\n        }\n\n        /// <summary>\n        /// Hides all application windows without minimizing them.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        public void Hide()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// Shows application windows after they were hidden. Does not automatically focus them.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        public void Show()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// The current application directory.\n        /// </summary>\n        public async Task<string> GetAppPathAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<string>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Sets or creates a directory your app's logs which can then be manipulated with <see cref=\"GetPathAsync\"/>\n        /// or <see cref=\"SetPath\"/>.\n        /// <para/>\n        /// Calling <see cref=\"SetAppLogsPath\"/> without a path parameter will result in this directory being set to\n        /// ~/Library/Logs/YourAppName on macOS, and inside the userData directory on Linux and Windows.\n        /// </summary>\n        /// <param name=\"path\">A custom path for your logs. Must be absolute.</param>\n        public void SetAppLogsPath(string path)\n        {\n            this.CallMethod1(path);\n        }\n\n        /// <summary>\n        /// The path to a special directory. If <see cref=\"GetPathAsync\"/> is called without called\n        /// <see cref=\"SetAppLogsPath\"/> being called first, a default directory will be created equivalent\n        /// to calling <see cref=\"SetAppLogsPath\"/> without a path parameter.\n        /// </summary>\n        /// <param name=\"pathName\">Special directory.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>A path to a special directory or file associated with name.</returns>\n        public async Task<string> GetPathAsync(PathName pathName, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var taskCompletionSource = new TaskCompletionSource<string>();\n            using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<string>(\"appGetPathCompleted\", taskCompletionSource.SetResult);\n                BridgeConnector.Socket.Emit(\"appGetPath\", pathName);\n\n                return await taskCompletionSource.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Overrides the path to a special directory or file associated with name. If the path specifies a directory\n        /// that does not exist, an Error is thrown. In that case, the directory should be created with fs.mkdirSync or similar.\n        /// <para/>\n        /// You can only override paths of a name defined in <see cref=\"GetPathAsync\"/>.\n        /// <para/>\n        /// By default, web pages' cookies and caches will be stored under the <see cref=\"PathName.UserData\"/> directory. If you\n        /// want to change this location, you have to override the <see cref=\"PathName.UserData\"/> path before the <see cref=\"Ready\"/>\n        /// event of the <see cref=\"App\"/> module is emitted.\n        /// <param name=\"name\">Special directory.</param>\n        /// <param name=\"path\">New path to a special directory.</param>\n        /// </summary>\n        public void SetPath(PathName name, string path)\n        {\n            this.CallMethod2(name, path);\n        }\n\n        /// <summary>\n        /// The version of the loaded application. If no version is found in the application’s package.json file,\n        /// the version of the current bundle or executable is returned.\n        /// </summary>\n        /// <returns>The version of the loaded application.</returns>\n        public async Task<string> GetVersionAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<string>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// The current application locale. Possible return values are documented <see href=\"https://www.electronjs.org/docs/api/locales\">here</see>.\n        /// <para/>\n        /// Note: When distributing your packaged app, you have to also ship the locales folder.\n        /// <para/>\n        /// Note: On Windows, you have to call it after the <see cref=\"Ready\"/> events gets emitted.\n        /// </summary>\n        /// <returns>The current application locale.</returns>\n        public async Task<string> GetLocaleAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<string>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Adds path to the recent documents list. This list is managed by the OS. On Windows you can visit the\n        /// list from the task bar, and on macOS you can visit it from dock menu.\n        /// </summary>\n        /// <param name=\"path\">Path to add.</param>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public void AddRecentDocument(string path)\n        {\n            this.CallMethod1(path);\n        }\n\n        /// <summary>\n        /// Clears the recent documents list.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public void ClearRecentDocuments()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to\n        /// integrate your app deeper into the operating system. Once registered, all links with your-protocol://\n        /// will be opened with the current executable. The whole link, including protocol, will be passed to your\n        /// application as a parameter.\n        /// <para/>\n        /// Note: On macOS, you can only register protocols that have been added to your app's info.plist, which\n        /// cannot be modified at runtime. However, you can change the file during build time via\n        /// <see href=\"https://www.electronforge.io/\">Electron Forge</see>,\n        /// <see href=\"https://github.com/electron/electron-packager\">Electron Packager</see>, or by editing info.plist\n        /// with a text editor. Please refer to\n        /// <see href=\"https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115\">Apple's documentation</see>\n        /// for details.\n        /// <para/>\n        /// Note: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but\n        /// the registry key it sets won't be accessible by other applications. In order to register your Windows Store\n        /// application as a default protocol handler you <see href=\"https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol\">must declare the protocol in your manifest</see>.\n        /// <para/>\n        /// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally.\n        /// </summary>\n        /// <param name=\"protocol\">\n        /// The name of your protocol, without ://. For example, if you want your app to handle electron:// links,\n        /// call this method with electron as the parameter.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the call succeeded.</returns>\n        public async Task<bool> SetAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default)\n        {\n            return await this.SetAsDefaultProtocolClientAsync(protocol, null, null, cancellationToken).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to\n        /// integrate your app deeper into the operating system. Once registered, all links with your-protocol://\n        /// will be opened with the current executable. The whole link, including protocol, will be passed to your\n        /// application as a parameter.\n        /// <para/>\n        /// Note: On macOS, you can only register protocols that have been added to your app's info.plist, which\n        /// cannot be modified at runtime. However, you can change the file during build time via\n        /// <see href=\"https://www.electronforge.io/\">Electron Forge</see>,\n        /// <see href=\"https://github.com/electron/electron-packager\">Electron Packager</see>, or by editing info.plist\n        /// with a text editor. Please refer to\n        /// <see href=\"https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115\">Apple's documentation</see>\n        /// for details.\n        /// <para/>\n        /// Note: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but\n        /// the registry key it sets won't be accessible by other applications. In order to register your Windows Store\n        /// application as a default protocol handler you <see href=\"https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol\">must declare the protocol in your manifest</see>.\n        /// <para/>\n        /// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally.\n        /// </summary>\n        /// <param name=\"protocol\">\n        /// The name of your protocol, without ://. For example, if you want your app to handle electron:// links,\n        /// call this method with electron as the parameter.</param>\n        /// <param name=\"path\">The path to the Electron executable. Defaults to process.execPath</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the call succeeded.</returns>\n        public async Task<bool> SetAsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default)\n        {\n            return await this.SetAsDefaultProtocolClientAsync(protocol, path, null, cancellationToken).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Sets the current executable as the default handler for a protocol (aka URI scheme). It allows you to\n        /// integrate your app deeper into the operating system. Once registered, all links with your-protocol://\n        /// will be opened with the current executable. The whole link, including protocol, will be passed to your\n        /// application as a parameter.\n        /// <para/>\n        /// Note: On macOS, you can only register protocols that have been added to your app's info.plist, which\n        /// cannot be modified at runtime. However, you can change the file during build time via\n        /// <see href=\"https://www.electronforge.io/\">Electron Forge</see>,\n        /// <see href=\"https://github.com/electron/electron-packager\">Electron Packager</see>, or by editing info.plist\n        /// with a text editor. Please refer to\n        /// <see href=\"https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115\">Apple's documentation</see>\n        /// for details.\n        /// <para/>\n        /// Note: In a Windows Store environment (when packaged as an appx) this API will return true for all calls but\n        /// the registry key it sets won't be accessible by other applications. In order to register your Windows Store\n        /// application as a default protocol handler you <see href=\"https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol\">must declare the protocol in your manifest</see>.\n        /// <para/>\n        /// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally.\n        /// </summary>\n        /// <param name=\"protocol\">\n        /// The name of your protocol, without ://. For example, if you want your app to handle electron:// links,\n        /// call this method with electron as the parameter.</param>\n        /// <param name=\"path\">The path to the Electron executable. Defaults to process.execPath</param>\n        /// <param name=\"args\">Arguments passed to the executable. Defaults to an empty array.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the call succeeded.</returns>\n        public async Task<bool> SetAsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var taskCompletionSource = new TaskCompletionSource<bool>();\n            using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<bool>(\"appSetAsDefaultProtocolClientCompleted\", taskCompletionSource.SetResult);\n                BridgeConnector.Socket.Emit(\"appSetAsDefaultProtocolClient\", protocol, path, args);\n\n                return await taskCompletionSource.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// This method checks if the current executable as the default handler for a protocol (aka URI scheme).\n        /// If so, it will remove the app as the default handler.\n        /// </summary>\n        /// <param name=\"protocol\">The name of your protocol, without ://.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the call succeeded.</returns>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public async Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default)\n        {\n            return await this.RemoveAsDefaultProtocolClientAsync(protocol, null, null, cancellationToken).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// This method checks if the current executable as the default handler for a protocol (aka URI scheme).\n        /// If so, it will remove the app as the default handler.\n        /// </summary>\n        /// <param name=\"protocol\">The name of your protocol, without ://.</param>\n        /// <param name=\"path\">Defaults to process.execPath.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the call succeeded.</returns>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public async Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default)\n        {\n            return await this.RemoveAsDefaultProtocolClientAsync(protocol, path, null, cancellationToken).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// This method checks if the current executable as the default handler for a protocol (aka URI scheme).\n        /// If so, it will remove the app as the default handler.\n        /// </summary>\n        /// <param name=\"protocol\">The name of your protocol, without ://.</param>\n        /// <param name=\"path\">Defaults to process.execPath.</param>\n        /// <param name=\"args\">Defaults to an empty array.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the call succeeded.</returns>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public async Task<bool> RemoveAsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var taskCompletionSource = new TaskCompletionSource<bool>();\n            using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<bool>(\"appRemoveAsDefaultProtocolClientCompleted\", taskCompletionSource.SetResult);\n                BridgeConnector.Socket.Emit(\"appRemoveAsDefaultProtocolClient\", protocol, path, args);\n\n                return await taskCompletionSource.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// This method checks if the current executable is the default handler for a protocol (aka URI scheme).\n        /// <para/>\n        /// Note: On macOS, you can use this method to check if the app has been registered as the default protocol\n        /// handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist\n        /// on the macOS machine. Please refer to <see href=\"https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme\">Apple's documentation</see>\n        /// for details.\n        /// <para/>\n        /// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally.\n        /// </summary>\n        /// <param name=\"protocol\">The name of your protocol, without ://.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the current executable is the default handler for a protocol (aka URI scheme).</returns>\n        public async Task<bool> IsDefaultProtocolClientAsync(string protocol, CancellationToken cancellationToken = default)\n        {\n            return await this.IsDefaultProtocolClientAsync(protocol, null, null, cancellationToken).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// This method checks if the current executable is the default handler for a protocol (aka URI scheme).\n        /// <para/>\n        /// Note: On macOS, you can use this method to check if the app has been registered as the default protocol\n        /// handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist\n        /// on the macOS machine. Please refer to <see href=\"https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme\">Apple's documentation</see>\n        /// for details.\n        /// <para/>\n        /// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally.\n        /// </summary>\n        /// <param name=\"protocol\">The name of your protocol, without ://.</param>\n        /// <param name=\"path\">Defaults to process.execPath.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the current executable is the default handler for a protocol (aka URI scheme).</returns>\n        public async Task<bool> IsDefaultProtocolClientAsync(string protocol, string path, CancellationToken cancellationToken = default)\n        {\n            return await this.IsDefaultProtocolClientAsync(protocol, path, null, cancellationToken).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// This method checks if the current executable is the default handler for a protocol (aka URI scheme).\n        /// <para/>\n        /// Note: On macOS, you can use this method to check if the app has been registered as the default protocol\n        /// handler for a protocol. You can also verify this by checking ~/Library/Preferences/com.apple.LaunchServices.plist\n        /// on the macOS machine. Please refer to <see href=\"https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme\">Apple's documentation</see>\n        /// for details.\n        /// <para/>\n        /// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally.\n        /// </summary>\n        /// <param name=\"protocol\">The name of your protocol, without ://.</param>\n        /// <param name=\"path\">Defaults to process.execPath.</param>\n        /// <param name=\"args\">Defaults to an empty array.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the current executable is the default handler for a protocol (aka URI scheme).</returns>\n        public async Task<bool> IsDefaultProtocolClientAsync(string protocol, string path, string[] args, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var taskCompletionSource = new TaskCompletionSource<bool>();\n            using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<bool>(\"appIsDefaultProtocolClientCompleted\", taskCompletionSource.SetResult);\n                BridgeConnector.Socket.Emit(\"appIsDefaultProtocolClient\", protocol, path, args);\n\n                return await taskCompletionSource.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Adds tasks to the <see cref=\"UserTask\"/> category of the JumpList on Windows.\n        /// <para/>\n        /// Note: If you'd like to customize the Jump List even more use <see cref=\"SetJumpList\"/> instead.\n        /// </summary>\n        /// <param name=\"userTasks\">Array of <see cref=\"UserTask\"/> objects.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the call succeeded.</returns>\n        [SupportedOSPlatform(\"Windows\")]\n        public async Task<bool> SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var taskCompletionSource = new TaskCompletionSource<bool>();\n            using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<bool>(\"appSetUserTasksCompleted\", taskCompletionSource.SetResult);\n                BridgeConnector.Socket.Emit(\"appSetUserTasks\", userTasks);\n\n                return await taskCompletionSource.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Jump List settings for the application.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Jump List settings.</returns>\n        [SupportedOSPlatform(\"Windows\")]\n        public async Task<JumpListSettings> GetJumpListSettingsAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<JumpListSettings>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Sets or removes a custom Jump List for the application. If categories is null the previously set custom\n        /// Jump List (if any) will be replaced by the standard Jump List for the app (managed by Windows).\n        /// <para/>\n        /// Note: If a <see cref=\"JumpListCategory\"/> object has neither the <see cref=\"JumpListCategory.Type\"/> nor\n        /// the <see cref=\"JumpListCategory.Name\"/> property set then its <see cref=\"JumpListCategory.Type\"/> is assumed\n        /// to be <see cref=\"JumpListCategoryType.tasks\"/>. If the <see cref=\"JumpListCategory.Name\"/> property is set but\n        /// the <see cref=\"JumpListCategory.Type\"/> property is omitted then the <see cref=\"JumpListCategory.Type\"/> is\n        /// assumed to be <see cref=\"JumpListCategoryType.custom\"/>.\n        /// <para/>\n        /// Note: Users can remove items from custom categories, and Windows will not allow a removed item to be added\n        /// back into a custom category until after the next successful call to <see cref=\"SetJumpList\"/>. Any attempt\n        /// to re-add a removed item to a custom category earlier than that will result in the entire custom category being\n        /// omitted from the Jump List. The list of removed items can be obtained using <see cref=\"GetJumpListSettingsAsync\"/>.\n        /// </summary>\n        /// <param name=\"categories\">Array of <see cref=\"JumpListCategory\"/> objects.</param>\n        [SupportedOSPlatform(\"Windows\")]\n        public void SetJumpList(JumpListCategory[] categories)\n        {\n            this.CallMethod1(categories);\n        }\n\n        /// <summary>\n        /// The return value of this method indicates whether or not this instance of your application successfully obtained\n        /// the lock. If it failed to obtain the lock, you can assume that another instance of your application is already\n        /// running with the lock and exit immediately.\n        /// <para/>\n        /// I.e.This method returns <see langword=\"true\"/> if your process is the primary instance of your application and your\n        /// app should continue loading. It returns <see langword=\"false\"/> if your process should immediately quit as it has\n        /// sent its parameters to another instance that has already acquired the lock.\n        /// <para/>\n        /// On macOS, the system enforces single instance automatically when users try to open a second instance of your app\n        /// in Finder, and the open-file and open-url events will be emitted for that.However when users start your app in\n        /// command line, the system's single instance mechanism will be bypassed, and you have to use this method to ensure\n        /// single instance.\n        /// </summary>\n        /// <param name=\"newInstanceOpened\">Lambda with an array of the second instance’s command line arguments.\n        /// The second parameter is the working directory path.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>This method returns false if your process is the primary instance of the application and your app\n        /// should continue loading. And returns true if your process has sent its parameters to another instance, and\n        /// you should immediately quit.\n        /// </returns>\n        public async Task<bool> RequestSingleInstanceLockAsync(Action<string[], string> newInstanceOpened, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var taskCompletionSource = new TaskCompletionSource<bool>();\n            using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<bool>(\"appRequestSingleInstanceLockCompleted\", taskCompletionSource.SetResult);\n\n                BridgeConnector.Socket.Off(\"secondInstance\");\n                BridgeConnector.Socket.On<JsonElement>(\"secondInstance\", (result) =>\n                {\n                    var arr = result.EnumerateArray();\n                    var e = arr.GetEnumerator();\n                    e.MoveNext();\n                    var args = e.Current.Deserialize<string[]>(JsonSerializerOptions.Default);\n                    e.MoveNext();\n                    var workingDirectory = e.Current.GetString();\n                    newInstanceOpened(args, workingDirectory);\n                });\n\n                BridgeConnector.Socket.Emit(\"appRequestSingleInstanceLock\");\n\n                return await taskCompletionSource.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Releases all locks that were created by makeSingleInstance. This will allow\n        /// multiple instances of the application to once again run side by side.\n        /// </summary>\n        public void ReleaseSingleInstanceLock()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// This method returns whether or not this instance of your app is currently holding the single instance lock.\n        /// You can request the lock with <see cref=\"RequestSingleInstanceLockAsync\"/> and release with\n        /// <see cref=\"ReleaseSingleInstanceLock\"/>.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        public async Task<bool> HasSingleInstanceLockAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<bool>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Creates an NSUserActivity and sets it as the current activity. The activity is\n        /// eligible for <see href=\"https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html\">Handoff</see>\n        /// to another device afterward.\n        /// </summary>\n        /// <param name=\"type\">Uniquely identifies the activity. Maps to <see href=\"https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType\">NSUserActivity.activityType</see>.</param>\n        /// <param name=\"userInfo\">App-specific state to store for use by another device.</param>\n        [SupportedOSPlatform(\"macOS\")]\n        public void SetUserActivity(string type, object userInfo)\n        {\n            SetUserActivity(type, userInfo, null);\n        }\n\n        /// <summary>\n        /// Creates an NSUserActivity and sets it as the current activity. The activity is\n        /// eligible for <see href=\"https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html\">Handoff</see>\n        /// to another device afterward.\n        /// </summary>\n        /// <param name=\"type\">\n        /// Uniquely identifies the activity. Maps to <see href=\"https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType\">NSUserActivity.activityType</see>.\n        /// </param>\n        /// <param name=\"userInfo\">App-specific state to store for use by another device.</param>\n        /// <param name=\"webpageUrl\">\n        /// The webpage to load in a browser if no suitable app is installed on the resuming device. The scheme must be http or https.\n        /// </param>\n        [SupportedOSPlatform(\"macOS\")]\n        public void SetUserActivity(string type, object userInfo, string webpageUrl)\n        {\n            this.CallMethod3(type, userInfo, webpageUrl);\n        }\n\n        /// <summary>\n        /// The type of the currently running activity.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        [SupportedOSPlatform(\"macOS\")]\n        public async Task<string> GetCurrentActivityTypeAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<string>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Invalidates the current <see href=\"https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html\">Handoff</see> user activity.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        public void InvalidateCurrentActivity()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// Marks the current <see href=\"https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html\">Handoff</see> user activity as inactive without invalidating it.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        public void ResignCurrentActivity()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// Changes the <see href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx\">Application User Model ID</see> to id.\n        /// </summary>\n        /// <param name=\"id\">Model Id.</param>\n        [SupportedOSPlatform(\"Windows\")]\n        public void SetAppUserModelId(string id)\n        {\n            this.CallMethod1(id);\n        }\n\n        /// TODO: Check new parameter which is a function [App.ImportCertificate]\n        /// <summary>\n        /// Imports the certificate in pkcs12 format into the platform certificate store.\n        /// callback is called with the result of import operation, a value of 0 indicates\n        /// success while any other value indicates failure according to chromium net_error_list.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Result of import. Value of 0 indicates success.</returns>\n        [SupportedOSPlatform(\"Linux\")]\n        public async Task<int> ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var taskCompletionSource = new TaskCompletionSource<int>();\n            using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<int>(\"appImportCertificateCompleted\", taskCompletionSource.SetResult);\n                BridgeConnector.Socket.Emit(\"appImportCertificate\", options);\n\n                return await taskCompletionSource.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Memory and cpu usage statistics of all the processes associated with the app.\n        /// </summary>\n        /// <returns>\n        /// Array of ProcessMetric objects that correspond to memory and cpu usage\n        /// statistics of all the processes associated with the app.\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// </returns>\n        public async Task<ProcessMetric[]> GetAppMetricsAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<ProcessMetric[]>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// The Graphics Feature Status from chrome://gpu/.\n        /// <para/>\n        /// Note: This information is only usable after the gpu-info-update event is emitted.\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// </summary>\n        public async Task<GPUFeatureStatus> GetGpuFeatureStatusAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<GPUFeatureStatus>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Sets the counter badge for current app. Setting the count to 0 will hide the badge.\n        /// On macOS it shows on the dock icon. On Linux it only works for Unity launcher.\n        /// <para/>\n        /// Note: Unity launcher requires the existence of a .desktop file to work, for more\n        /// information please read <see href=\"https://www.electronjs.org/docs/tutorial/desktop-environment-integration#unity-launcher\">Desktop Environment Integration</see>.\n        /// </summary>\n        /// <param name=\"count\">Counter badge.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the call succeeded.</returns>\n        [SupportedOSPlatform(\"Linux\")]\n        [SupportedOSPlatform(\"macOS\")]\n        public async Task<bool> SetBadgeCountAsync(int count, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var taskCompletionSource = new TaskCompletionSource<bool>();\n            using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<bool>(\"appSetBadgeCountCompleted\", taskCompletionSource.SetResult);\n                BridgeConnector.Socket.Emit(\"appSetBadgeCount\", count);\n\n                return await taskCompletionSource.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// The current value displayed in the counter badge.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        [SupportedOSPlatform(\"Linux\")]\n        [SupportedOSPlatform(\"macOS\")]\n        public async Task<int> GetBadgeCountAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<int>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// A <see cref=\"CommandLine\"/> object that allows you to read and manipulate the command line arguments that Chromium uses.\n        /// </summary>\n        public CommandLine CommandLine { get; internal set; }\n\n        /// <summary>\n        /// Whether the current desktop environment is Unity launcher.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        [SupportedOSPlatform(\"Linux\")]\n        public async Task<bool> IsUnityRunningAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<bool>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// If you provided path and args options to <see cref=\"SetLoginItemSettings\"/> then you need to pass the same\n        /// arguments here for <see cref=\"LoginItemSettings.OpenAtLogin\"/> to be set correctly.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public async Task<LoginItemSettings> GetLoginItemSettingsAsync(CancellationToken cancellationToken = default)\n        {\n            return await this.GetLoginItemSettingsAsync(null, cancellationToken).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// If you provided path and args options to <see cref=\"SetLoginItemSettings\"/> then you need to pass the same\n        /// arguments here for <see cref=\"LoginItemSettings.OpenAtLogin\"/> to be set correctly.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public async Task<LoginItemSettings> GetLoginItemSettingsAsync(LoginItemSettingsOptions options, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var taskCompletionSource = new TaskCompletionSource<LoginItemSettings>();\n            using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<LoginItemSettings>(\"appGetLoginItemSettingsCompleted\", taskCompletionSource.SetResult);\n\n                if (options == null)\n                {\n                    BridgeConnector.Socket.Emit(\"appGetLoginItemSettings\");\n                }\n                else\n                {\n                    BridgeConnector.Socket.Emit(\"appGetLoginItemSettings\", options);\n                }\n\n                return await taskCompletionSource.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Set the app's login item settings.\n        /// To work with Electron's autoUpdater on Windows, which uses <see href=\"https://github.com/Squirrel/Squirrel.Windows\">Squirrel</see>,\n        /// you'll want to set the launch path to Update.exe, and pass arguments that specify your application name.\n        /// </summary>\n        /// <param name=\"loginSettings\"></param>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public void SetLoginItemSettings(LoginSettings loginSettings)\n        {\n            this.CallMethod1(loginSettings);\n        }\n\n        /// <summary>\n        /// <see langword=\"true\"/> if Chrome's accessibility support is enabled, <see langword=\"false\"/> otherwise. This API will\n        /// return <see langword=\"true\"/> if the use of assistive technologies, such as screen readers, has been detected.\n        /// See <see href=\"chromium.org/developers/design-documents/accessibility\">Chromium's accessibility docs</see> for more details.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if Chrome’s accessibility support is enabled, <see langword=\"false\"/> otherwise.</returns>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public async Task<bool> IsAccessibilitySupportEnabledAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return await this.InvokeAsync<bool>().ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Manually enables Chrome's accessibility support, allowing to expose accessibility switch to users in application settings.\n        /// See <see href=\"chromium.org/developers/design-documents/accessibility\">Chromium's accessibility docs</see> for more details.\n        /// Disabled (<see langword=\"false\"/>) by default.\n        /// <para/>\n        /// This API must be called after the <see cref=\"Ready\"/> event is emitted.\n        /// <para/>\n        /// Note: Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default.\n        /// </summary>\n        /// <param name=\"enabled\">Enable or disable <see href=\"https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree\">accessibility tree</see> rendering.</param>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public void SetAccessibilitySupportEnabled(bool enabled)\n        {\n            this.CallMethod1(enabled);\n        }\n\n        /// <summary>\n        /// Show the app's about panel options. These options can be overridden with\n        /// <see cref=\"SetAboutPanelOptions\"/>.\n        /// </summary>\n        public void ShowAboutPanel()\n        {\n            this.CallMethod0();\n        }\n\n        /// <summary>\n        /// Set the about panel options. This will override the values defined in the app's .plist file on macOS. See the\n        /// <see href=\"https://developer.apple.com/reference/appkit/nsapplication/1428479-orderfrontstandardaboutpanelwith?language=objc\">Apple docs</see>\n        /// for more details. On Linux, values must be set in order to be shown; there are no defaults.\n        /// <para/>\n        /// If you do not set credits but still wish to surface them in your app, AppKit will look for a file named \"Credits.html\",\n        /// \"Credits.rtf\", and \"Credits.rtfd\", in that order, in the bundle returned by the NSBundle class method main. The first file\n        /// found is used, and if none is found, the info area is left blank. See Apple\n        /// <see href=\"https://developer.apple.com/documentation/appkit/nsaboutpaneloptioncredits?language=objc\">documentation</see> for more information.\n        /// </summary>\n        /// <param name=\"options\">About panel options.</param>\n        public void SetAboutPanelOptions(AboutPanelOptions options)\n        {\n            this.CallMethod1(options);\n        }\n\n        /// <summary>\n        /// A <see cref=\"string\"/> which is the user agent string Electron will use as a global fallback.\n        /// <para/>\n        /// This is the user agent that will be used when no user agent is set at the webContents or\n        /// session level. It is useful for ensuring that your entire app has the same user agent. Set to a\n        /// custom value as early as possible in your app's initialization to ensure that your overridden value\n        /// is used.\n        /// </summary>\n        public string UserAgentFallback\n        {\n            [Obsolete(\"Use the asynchronous version UserAgentFallbackAsync instead\")]\n            get\n            {\n                return UserAgentFallbackAsync.Result;\n            }\n            set\n            {\n                BridgeConnector.Socket.Emit(\"appSetUserAgentFallback\", value);\n            }\n        }\n\n        /// <summary>\n        /// A <see cref=\"string\"/> which is the user agent string Electron will use as a global fallback.\n        /// <para/>\n        /// This is the user agent that will be used when no user agent is set at the webContents or\n        /// session level. It is useful for ensuring that your entire app has the same user agent. Set to a\n        /// custom value as early as possible in your app's initialization to ensure that your overridden value\n        /// is used.\n        /// </summary>\n        public Task<string> UserAgentFallbackAsync\n        {\n            get\n            {\n                return Task.Run(() =>\n                {\n                    var taskCompletionSource = new TaskCompletionSource<string>();\n\n                    BridgeConnector.Socket.Once<string>(\"appGetUserAgentFallbackCompleted\", taskCompletionSource.SetResult);\n                    BridgeConnector.Socket.Emit(\"appGetUserAgentFallback\");\n\n                    return taskCompletionSource.Task;\n                });\n            }\n        }\n\n        internal void PreventQuit()\n        {\n            _preventQuit = true;\n        }\n\n        private bool _preventQuit = false;\n\n        private const string ModuleName = \"app\";\n\n        /// <summary>\n        /// Subscribe to an unmapped event on the <see cref=\"App\"/> module.\n        /// </summary>\n        /// <param name=\"eventName\">The event name</param>\n        /// <param name=\"action\">The handler</param>\n        public void On(string eventName, Action action)\n            => Events.Instance.On(ModuleName, eventName, action);\n\n        /// <summary>\n        /// Subscribe to an unmapped event on the <see cref=\"App\"/> module.\n        /// </summary>\n        /// <param name=\"eventName\">The event name</param>\n        /// <param name=\"action\">The handler</param>\n        public async Task On(string eventName, Action<object> action)\n            => await Events.Instance.On(ModuleName, eventName, action).ConfigureAwait(false);\n\n        /// <summary>\n        /// Subscribe to an unmapped event on the <see cref=\"App\"/> module once.\n        /// </summary>\n        /// <param name=\"eventName\">The event name</param>\n        /// <param name=\"action\">The handler</param>\n        public void Once(string eventName, Action action)\n            => Events.Instance.Once(ModuleName, eventName, action);\n\n        /// <summary>\n        /// Subscribe to an unmapped event on the <see cref=\"App\"/> module once.\n        /// </summary>\n        /// <param name=\"eventName\">The event name</param>\n        /// <param name=\"action\">The handler</param>\n        public async Task Once(string eventName, Action<object> action)\n            => await Events.Instance.Once(ModuleName, eventName, action).ConfigureAwait(false);\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/AutoUpdater.cs",
    "content": "using ElectronNET.API.Entities;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\n// ReSharper disable InconsistentNaming\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Enable apps to automatically update themselves. Based on electron-updater.\n    /// </summary>\n    public sealed class AutoUpdater : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n        protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;\n        protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;\n\n        /// <summary>\n        /// Whether to automatically download an update when it is found. (Default is true)\n        /// </summary>\n        public bool AutoDownload\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<bool>()).Result;\n            }\n            set\n            {\n                BridgeConnector.Socket.Emit(\"autoUpdater-autoDownload-set\", value);\n            }\n        }\n\n        /// <summary>\n        /// Whether to automatically install a downloaded update on app quit (if `QuitAndInstall` was not called before).\n        /// \n        /// Applicable only on Windows and Linux.\n        /// </summary>\n        public bool AutoInstallOnAppQuit\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<bool>()).Result;\n            }\n            set\n            {\n                BridgeConnector.Socket.Emit(\"autoUpdater-autoInstallOnAppQuit-set\", value);\n            }\n        }\n\n        /// <summary>\n        /// *GitHub provider only.* Whether to allow update to pre-release versions.\n        /// Defaults to \"true\" if application version contains prerelease components (e.g. \"0.12.1-alpha.1\", here \"alpha\" is a prerelease component), otherwise \"false\".\n        /// \n        /// If \"true\", downgrade will be allowed(\"allowDowngrade\" will be set to \"true\").\n        /// </summary>\n        public bool AllowPrerelease\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<bool>()).Result;\n            }\n            set\n            {\n                BridgeConnector.Socket.Emit(\"autoUpdater-allowPrerelease-set\", value);\n            }\n        }\n\n        /// <summary>\n        /// *GitHub provider only.*\n        /// Get all release notes (from current version to latest), not just the latest (Default is false).\n        /// </summary>\n        public bool FullChangelog\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<bool>()).Result;\n            }\n            set\n            {\n                BridgeConnector.Socket.Emit(\"autoUpdater-fullChangelog-set\", value);\n            }\n        }\n\n        /// <summary>\n        /// Whether to allow version downgrade (when a user from the beta channel wants to go back to the stable channel).\n        /// Taken in account only if channel differs (pre-release version component in terms of semantic versioning).\n        /// Default is false.\n        /// </summary>\n        public bool AllowDowngrade\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<bool>()).Result;\n            }\n            set\n            {\n                BridgeConnector.Socket.Emit(\"autoUpdater-allowDowngrade-set\", value);\n            }\n        }\n\n        /// <summary>\n        /// For test only.\n        /// </summary>\n        public string UpdateConfigPath\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<string>()).Result;\n            }\n        }\n\n        /// <summary>\n        /// The current application version\n        /// </summary>\n        public Task<SemVer> CurrentVersionAsync\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<SemVer>());\n            }\n        }\n\n        /// <summary>\n        /// Get the update channel. Not applicable for GitHub.\n        /// Doesn’t return channel from the update configuration, only if was previously set.\n        /// </summary>\n        [Obsolete(\"Use the asynchronous version ChannelAsync instead\")]\n        public string Channel\n        {\n            get\n            {\n                return ChannelAsync.Result;\n            }\n        }\n\n        /// <summary>\n        /// Get the update channel. Not applicable for GitHub.\n        /// Doesn’t return channel from the update configuration, only if was previously set.\n        /// </summary>\n        public Task<string> ChannelAsync\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<string>());\n            }\n        }\n\n        /// <summary>\n        /// Set the update channel. Not applicable for GitHub.\n        /// </summary>\n        public string SetChannel\n        {\n            set\n            {\n                BridgeConnector.Socket.Emit(\"autoUpdater-channel-set\", value);\n            }\n        }\n\n\n        /// <summary>\n        /// The request headers.\n        /// </summary>\n        public Task<Dictionary<string, string>> RequestHeadersAsync\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<Dictionary<string, string>>());\n            }\n        }\n\n        /// <summary>\n        /// The request headers.\n        /// </summary>\n        public Dictionary<string, string> RequestHeaders\n        {\n            set\n            {\n                BridgeConnector.Socket.Emit(\"autoUpdater-requestHeaders-set\", value);\n            }\n        }\n\n        /// <summary>\n        /// Emitted when there is an error while updating.\n        /// </summary>\n        public event Action<string> OnError\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when checking if an update has started.\n        /// </summary>\n        public event Action OnCheckingForUpdate\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when there is an available update.\n        /// The update is downloaded automatically if AutoDownload is true.\n        /// </summary>\n        public event Action<UpdateInfo> OnUpdateAvailable\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when there is no available update.\n        /// </summary>\n        public event Action<UpdateInfo> OnUpdateNotAvailable\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted on download progress.\n        /// </summary>\n        public event Action<ProgressInfo> OnDownloadProgress\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted on download complete.\n        /// </summary>\n        public event Action<UpdateInfo> OnUpdateDownloaded\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        private static AutoUpdater _autoUpdater;\n        private static object _syncRoot = new object();\n\n        internal AutoUpdater()\n        {\n        }\n\n        internal static AutoUpdater Instance\n        {\n            get\n            {\n                if (_autoUpdater == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_autoUpdater == null)\n                        {\n                            _autoUpdater = new AutoUpdater();\n                        }\n                    }\n                }\n\n                return _autoUpdater;\n            }\n        }\n\n        /// <summary>\n        /// Asks the server whether there is an update.\n        /// </summary>\n        /// <returns></returns>\n        public Task<UpdateCheckResult> CheckForUpdatesAsync()\n        {\n            var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<UpdateCheckResult>(\"autoUpdater-checkForUpdates-completed\" + guid, (result) =>\n            {\n                try\n                {\n                    BridgeConnector.Socket.Off(\"autoUpdater-checkForUpdatesError\" + guid);\n                    taskCompletionSource.SetResult(result);\n                }\n                catch (Exception ex)\n                {\n                    taskCompletionSource.SetException(ex);\n                }\n            });\n            BridgeConnector.Socket.Once<string>(\"autoUpdater-checkForUpdatesError\" + guid, (result) =>\n            {\n                BridgeConnector.Socket.Off(\"autoUpdater-checkForUpdates-completed\" + guid);\n                string message = \"An error occurred in CheckForUpdatesAsync\";\n                if (!string.IsNullOrEmpty(result)) message = result;\n                taskCompletionSource.SetException(new Exception(message));\n            });\n\n            BridgeConnector.Socket.Emit(\"autoUpdater-checkForUpdates\", guid);\n\n            return taskCompletionSource.Task;\n        }\n\n        /// <summary>\n        /// Asks the server whether there is an update.\n        /// \n        /// This will immediately download an update, then install when the app quits.\n        /// </summary>\n        /// <returns></returns>\n        public Task<UpdateCheckResult> CheckForUpdatesAndNotifyAsync()\n        {\n            var taskCompletionSource = new TaskCompletionSource<UpdateCheckResult>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<UpdateCheckResult>(\"autoUpdater-checkForUpdatesAndNotify-completed\" + guid, (result) =>\n            {\n                try\n                {\n                    BridgeConnector.Socket.Off(\"autoUpdater-checkForUpdatesAndNotifyError\" + guid);\n                    taskCompletionSource.SetResult(result);\n                }\n                catch (Exception ex)\n                {\n                    taskCompletionSource.SetException(ex);\n                }\n            });\n            BridgeConnector.Socket.Once<string>(\"autoUpdater-checkForUpdatesAndNotifyError\" + guid, (result) =>\n            {\n                BridgeConnector.Socket.Off(\"autoUpdater-checkForUpdatesAndNotify-completed\" + guid);\n                string message = \"An error occurred in CheckForUpdatesAndNotifyAsync\";\n                if (!string.IsNullOrEmpty(result)) message = result;\n                taskCompletionSource.SetException(new Exception(message));\n            });\n\n            BridgeConnector.Socket.Emit(\"autoUpdater-checkForUpdatesAndNotify\", guid);\n\n            return taskCompletionSource.Task;\n        }\n\n        /// <summary>\n        ///    Restarts the app and installs the update after it has been downloaded.\n        ///    It should only be called after `update-downloaded` has been emitted.\n        ///\n        ///    Note: QuitAndInstall() will close all application windows first and only emit `before-quit` event on `app` after that.\n        ///    This is different from the normal quit event sequence.\n        /// </summary>\n        /// <param name=\"isSilent\">*windows-only* Runs the installer in silent mode. Defaults to `false`.</param>\n        /// <param name=\"isForceRunAfter\">Run the app after finish even on silent install. Not applicable for macOS. Ignored if `isSilent` is set to `false`.</param>\n        public void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false)\n        {\n            BridgeConnector.Socket.Emit(\"autoUpdater-quitAndInstall\", isSilent, isForceRunAfter);\n        }\n\n        /// <summary>\n        /// Start downloading update manually. You can use this method if \"AutoDownload\" option is set to \"false\".\n        /// </summary>\n        /// <returns>Path to downloaded file.</returns>\n        public Task<string> DownloadUpdateAsync()\n        {\n            var tcs = new TaskCompletionSource<string>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<string>(\"autoUpdater-downloadUpdate-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"autoUpdater-downloadUpdate\", guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Feed URL.\n        /// </summary>\n        /// <returns>Feed URL.</returns>\n        public Task<string> GetFeedURLAsync()\n        {\n            var tcs = new TaskCompletionSource<string>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<string>(\"autoUpdater-getFeedURL-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"autoUpdater-getFeedURL\", guid);\n\n            return tcs.Task;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/BrowserView.cs",
    "content": "using ElectronNET.API.Entities;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// A BrowserView can be used to embed additional web content into a BrowserWindow.\n    /// It is like a child window, except that it is positioned relative to its owning window.\n    /// It is meant to be an alternative to the webview tag.\n    /// </summary>\n    public class BrowserView : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n        protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;\n\n        /// <summary>\n        /// Gets the identifier.\n        /// </summary>\n        public override int Id { get; protected set; }\n\n        /// <summary>\n        /// Render and control web pages.\n        /// </summary>\n        public WebContents WebContents { get; internal set; }\n\n        /// <summary>\n        /// Resizes and moves the view to the supplied bounds relative to the window.\n        /// (experimental)\n        /// </summary>\n        public Rectangle Bounds\n        {\n            get\n            {\n                return Task.Run(() => this.InvokeAsync<Rectangle>()).Result;\n            }\n            set\n            {\n                BridgeConnector.Socket.Emit(\"browserView-bounds-set\", Id, value);\n            }\n        }\n\n        /// <summary>\n        /// BrowserView\n        /// </summary>\n        internal BrowserView(int id)\n        {\n            Id = id;\n\n            // Workaround: increase the Id so as not to conflict with BrowserWindow id\n            // the backend detect about the value an BrowserView\n            WebContents = new WebContents(id + 1000);\n        }\n\n        /// <summary>\n        /// (experimental)\n        /// </summary>\n        /// <param name=\"options\"></param>\n        public void SetAutoResize(AutoResizeOptions options)\n        {\n            BridgeConnector.Socket.Emit(\"browserView-setAutoResize\", Id, options);\n        }\n\n        /// <summary>\n        /// Color in #aarrggbb or #argb form. The alpha channel is optional.\n        /// (experimental)\n        /// </summary>\n        /// <param name=\"color\">Color in #aarrggbb or #argb form. The alpha channel is optional.</param>\n        public void SetBackgroundColor(string color)\n        {\n            BridgeConnector.Socket.Emit(\"browserView-setBackgroundColor\", Id, color);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/BrowserWindow.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Runtime.Versioning;\nusing System.Threading.Tasks;\nusing ElectronNET.API.Entities;\nusing ElectronNET.API.Extensions;\n\n// ReSharper disable InconsistentNaming\n\nnamespace ElectronNET.API;\n\n/// <summary>\n/// Create and control browser windows.\n/// </summary>\npublic class BrowserWindow : ApiBase\n{\n    protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n    protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;\n\n    /// <summary>\n    /// Gets the identifier.\n    /// </summary>\n    /// <value>\n    /// The identifier.\n    /// </value>\n    public override int Id { get; protected set; }\n\n    /// <summary>\n    /// Emitted when the web page has been rendered (while not being shown) and\n    /// window can be displayed without a visual flash.\n    /// </summary>\n    public event Action OnReadyToShow\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the document changed its title.\n    /// </summary>\n    public event Action<string> OnPageTitleUpdated\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window is going to be closed.\n    /// </summary>\n    public event Action OnClose\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window is closed.\n    /// After you have received this event you should remove the\n    /// reference to the window and avoid using it any more.\n    /// </summary>\n    public event Action OnClosed\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when window session is going to end due to force shutdown or machine restart or session log off.\n    /// </summary>\n    [SupportedOSPlatform(\"Windows\")]\n    public event Action OnSessionEnd\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the web page becomes unresponsive.\n    /// </summary>\n    public event Action OnUnresponsive\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the unresponsive web page becomes responsive again.\n    /// </summary>\n    public event Action OnResponsive\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window loses focus.\n    /// </summary>\n    public event Action OnBlur\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window gains focus.\n    /// </summary>\n    public event Action OnFocus\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window is shown.\n    /// </summary>\n    public event Action OnShow\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window is hidden.\n    /// </summary>\n    public event Action OnHide\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when window is maximized.\n    /// </summary>\n    public event Action OnMaximize\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window exits from a maximized state.\n    /// </summary>\n    public event Action OnUnmaximize\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window is minimized.\n    /// </summary>\n    public event Action OnMinimize\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window is restored from a minimized state.\n    /// </summary>\n    public event Action OnRestore\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window is being resized.\n    /// </summary>\n    public event Action OnResize\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window is being moved to a new position.\n    /// \n    /// Note: On macOS this event is just an alias of moved.\n    /// </summary>\n    public event Action OnMove\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window is moved or resized.\n    /// </summary>\n    /// <remarks>\n    ///     While not being an original Electron event, this one includes the bounds values,\n    ///     saving the additional roundtrip for calling <see cref=\"GetBoundsAsync\"/>.\n    /// </remarks>\n    public event Action<Rectangle> OnBoundsChanged\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// macOS: Emitted once when the window is moved to a new position.\n    /// </summary>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public event Action OnMoved\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window enters a full-screen state.\n    /// </summary>\n    public event Action OnEnterFullScreen\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window leaves a full-screen state.\n    /// </summary>\n    public event Action OnLeaveFullScreen\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window enters a full-screen state triggered by HTML API.\n    /// </summary>\n    public event Action OnEnterHtmlFullScreen\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window leaves a full-screen state triggered by HTML API.\n    /// </summary>\n    public event Action OnLeaveHtmlFullScreen\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when an App Command is invoked. These are typically related to\n    /// keyboard media keys or browser commands, as well as the “Back” button\n    /// built into some mice on Windows.\n    /// \n    /// Commands are lowercased, underscores are replaced with hyphens,\n    /// and the APPCOMMAND_ prefix is stripped off.e.g.APPCOMMAND_BROWSER_BACKWARD\n    /// is emitted as browser-backward.\n    /// </summary>\n    [SupportedOSPlatform(\"Windows\")]\n    [SupportedOSPlatform(\"Linux\")]\n    public event Action<string> OnAppCommand\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted on 3-finger swipe. Possible directions are up, right, down, left.\n    /// </summary>\n    [SupportedOSPlatform(\"macOS\")]\n    public event Action<string> OnSwipe\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window opens a sheet.\n    /// </summary>\n    [SupportedOSPlatform(\"macOS\")]\n    public event Action OnSheetBegin\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the window has closed a sheet.\n    /// </summary>\n    [SupportedOSPlatform(\"macOS\")]\n    public event Action OnSheetEnd\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the native new tab button is clicked.\n    /// </summary>\n    [SupportedOSPlatform(\"macOS\")]\n    public event Action OnNewWindowForTab\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    internal BrowserWindow(int id)\n    {\n        Id = id;\n        WebContents = new WebContents(id);\n    }\n\n    /// <summary>\n    /// Force closing the window, the unload and beforeunload event won’t be\n    /// emitted for the web page, and close event will also not be emitted\n    /// for this window, but it guarantees the closed event will be emitted.\n    /// </summary>\n    public void Destroy() => this.CallMethod0();\n\n    /// <summary>\n    /// Try to close the window. This has the same effect as a user manually\n    /// clicking the close button of the window. The web page may cancel the close though.\n    /// </summary>\n    public void Close() => this.CallMethod0();\n\n    /// <summary>\n    /// Focuses on the window.\n    /// </summary>\n    public void Focus() => this.CallMethod0();\n\n    /// <summary>\n    /// Removes focus from the window.\n    /// </summary>\n    public void Blur() => this.CallMethod0();\n\n    /// <summary>\n    /// Whether the window is focused.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsFocusedAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Whether the window is destroyed.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsDestroyedAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Shows and gives focus to the window.\n    /// </summary>\n    public void Show() => this.CallMethod0();\n\n    /// <summary>\n    /// Shows the window but doesn’t focus on it.\n    /// </summary>\n    public void ShowInactive() => this.CallMethod0();\n\n    /// <summary>\n    /// Hides the window.\n    /// </summary>\n    public void Hide() => this.CallMethod0();\n\n    /// <summary>\n    /// Whether the window is visible to the user.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsVisibleAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Whether current window is a modal window.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsModalAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Maximizes the window. This will also show (but not focus) the window if it isn’t being displayed already.\n    /// </summary>\n    public void Maximize() => this.CallMethod0();\n\n    /// <summary>\n    /// Unmaximizes the window.\n    /// </summary>\n    public void Unmaximize() => this.CallMethod0();\n\n    /// <summary>\n    /// Whether the window is maximized.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsMaximizedAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Minimizes the window. On some platforms the minimized window will be shown in the Dock.\n    /// </summary>\n    public void Minimize() => this.CallMethod0();\n\n    /// <summary>\n    /// Restores the window from minimized state to its previous state.\n    /// </summary>\n    public void Restore() => this.CallMethod0();\n\n    /// <summary>\n    /// Whether the window is minimized.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsMinimizedAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Sets whether the window should be in fullscreen mode.\n    /// </summary>\n    /// <param name=\"flag\"></param>\n    public void SetFullScreen(bool flag) => this.CallMethod1(flag);\n\n    /// <summary>\n    /// Whether the window is in fullscreen mode.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsFullScreenAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// This will make a window maintain an aspect ratio. The extra size allows a developer to have space,\n    /// specified in pixels, not included within the aspect ratio calculations. This API already takes into\n    /// account the difference between a window’s size and its content size.\n    ///\n    /// Consider a normal window with an HD video player and associated controls.Perhaps there are 15 pixels\n    /// of controls on the left edge, 25 pixels of controls on the right edge and 50 pixels of controls below\n    /// the player. In order to maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within\n    /// the player itself we would call this function with arguments of 16/9 and[40, 50]. The second argument\n    /// doesn’t care where the extra width and height are within the content view–only that they exist. Just\n    /// sum any extra width and height areas you have within the overall content view.\n    /// </summary>\n    /// <param name=\"aspectRatio\">The aspect ratio to maintain for some portion of the content view.</param>\n    /// <param name=\"extraSize\">The extra size not to be included while maintaining the aspect ratio.</param>\n    public void SetAspectRatio(double aspectRatio, Size extraSize) =>\n        this.CallMethod2(aspectRatio, extraSize);\n\n    /// <summary>\n    /// This will make a window maintain an aspect ratio. The extra size allows a developer to have space,\n    /// specified in pixels, not included within the aspect ratio calculations. This API already takes into\n    /// account the difference between a window’s size and its content size.\n    ///\n    /// Consider a normal window with an HD video player and associated controls.Perhaps there are 15 pixels\n    /// of controls on the left edge, 25 pixels of controls on the right edge and 50 pixels of controls below\n    /// the player. In order to maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within\n    /// the player itself we would call this function with arguments of 16/9 and[40, 50]. The second argument\n    /// doesn’t care where the extra width and height are within the content view–only that they exist. Just\n    /// sum any extra width and height areas you have within the overall content view.\n    /// </summary>\n    /// <param name=\"aspectRatio\">The aspect ratio to maintain for some portion of the content view.</param>\n    /// <param name=\"extraSize\">The extra size not to be included while maintaining the aspect ratio.</param>\n    public void SetAspectRatio(int aspectRatio, Size extraSize) =>\n        this.CallMethod2(aspectRatio, extraSize);\n\n    /// <summary>\n    /// Uses Quick Look to preview a file at a given path.\n    /// </summary>\n    /// <param name=\"path\">The absolute path to the file to preview with QuickLook. This is important as\n    /// Quick Look uses the file name and file extension on the path to determine the content type of the\n    /// file to open.</param>\n    [SupportedOSPlatform(\"macOS\")]\n    public void PreviewFile(string path) => this.CallMethod1(path);\n\n    /// <summary>\n    /// Uses Quick Look to preview a file at a given path.\n    /// </summary>\n    /// <param name=\"path\">The absolute path to the file to preview with QuickLook. This is important as\n    /// Quick Look uses the file name and file extension on the path to determine the content type of the\n    /// file to open.</param>\n    /// <param name=\"displayname\">The name of the file to display on the Quick Look modal view. This is\n    /// purely visual and does not affect the content type of the file. Defaults to path.</param>\n    [SupportedOSPlatform(\"macOS\")]\n    public void PreviewFile(string path, string displayname) => this.CallMethod2(path, displayname);\n\n    /// <summary>\n    /// Closes the currently open Quick Look panel.\n    /// </summary>\n    [SupportedOSPlatform(\"macOS\")]\n    public void CloseFilePreview() => this.CallMethod0();\n\n    /// <summary>\n    /// Resizes and moves the window to the supplied bounds\n    /// </summary>\n    /// <param name=\"bounds\"></param>\n    public void SetBounds(Rectangle bounds) => this.CallMethod1(bounds);\n\n    /// <summary>\n    /// Resizes and moves the window to the supplied bounds\n    /// </summary>\n    /// <param name=\"bounds\"></param>\n    /// <param name=\"animate\"></param>\n    public void SetBounds(Rectangle bounds, bool animate) => this.CallMethod2(bounds, animate);\n\n    /// <summary>\n    /// Gets the bounds asynchronous.\n    /// </summary>\n    /// <returns></returns>\n    public Task<Rectangle> GetBoundsAsync() => this.InvokeAsync<Rectangle>();\n\n    /// <summary>\n    /// Resizes and moves the window’s client area (e.g. the web page) to the supplied bounds.\n    /// </summary>\n    /// <param name=\"bounds\"></param>\n    public void SetContentBounds(Rectangle bounds) => this.CallMethod1(bounds);\n\n    /// <summary>\n    /// Resizes and moves the window’s client area (e.g. the web page) to the supplied bounds.\n    /// </summary>\n    /// <param name=\"bounds\"></param>\n    /// <param name=\"animate\"></param>\n    public void SetContentBounds(Rectangle bounds, bool animate) => this.CallMethod2(bounds, animate);\n\n    /// <summary>\n    /// Gets the content bounds asynchronous.\n    /// </summary>\n    /// <returns></returns>\n    public Task<Rectangle> GetContentBoundsAsync() => this.InvokeAsync<Rectangle>();\n\n    /// <summary>\n    /// Resizes the window to width and height.\n    /// </summary>\n    /// <param name=\"width\"></param>\n    /// <param name=\"height\"></param>\n    public void SetSize(int width, int height) => this.CallMethod2(width, height);\n\n    /// <summary>\n    /// Resizes the window to width and height.\n    /// </summary>\n    /// <param name=\"width\"></param>\n    /// <param name=\"height\"></param>\n    /// <param name=\"animate\"></param>\n    public void SetSize(int width, int height, bool animate) => this.CallMethod3(width, height, animate);\n\n    /// <summary>\n    /// Contains the window’s width and height.\n    /// </summary>\n    /// <returns></returns>\n    public Task<int[]> GetSizeAsync() => this.InvokeAsync<int[]>();\n\n    /// <summary>\n    /// Resizes the window’s client area (e.g. the web page) to width and height.\n    /// </summary>\n    /// <param name=\"width\"></param>\n    /// <param name=\"height\"></param>\n    public void SetContentSize(int width, int height) => this.CallMethod2(width, height);\n\n    /// <summary>\n    /// Resizes the window’s client area (e.g. the web page) to width and height.\n    /// </summary>\n    /// <param name=\"width\"></param>\n    /// <param name=\"height\"></param>\n    /// <param name=\"animate\"></param>\n    public void SetContentSize(int width, int height, bool animate) => this.CallMethod3(width, height, animate);\n\n    /// <summary>\n    /// Contains the window’s client area’s width and height.\n    /// </summary>\n    /// <returns></returns>\n    public Task<int[]> GetContentSizeAsync() => this.InvokeAsync<int[]>();\n\n    /// <summary>\n    /// Sets the minimum size of window to width and height.\n    /// </summary>\n    /// <param name=\"width\"></param>\n    /// <param name=\"height\"></param>\n    public void SetMinimumSize(int width, int height) => this.CallMethod2(width, height);\n\n    /// <summary>\n    /// Contains the window’s minimum width and height.\n    /// </summary>\n    /// <returns></returns>\n    public Task<int[]> GetMinimumSizeAsync() => this.InvokeAsync<int[]>();\n\n    /// <summary>\n    /// Sets the maximum size of window to width and height.\n    /// </summary>\n    /// <param name=\"width\"></param>\n    /// <param name=\"height\"></param>\n    public void SetMaximumSize(int width, int height) => this.CallMethod2(width, height);\n\n    /// <summary>\n    /// Contains the window’s maximum width and height.\n    /// </summary>\n    /// <returns></returns>\n    public Task<int[]> GetMaximumSizeAsync() => this.InvokeAsync<int[]>();\n\n    /// <summary>\n    /// Sets whether the window can be manually resized by user.\n    /// </summary>\n    /// <param name=\"resizable\"></param>\n    public void SetResizable(bool resizable) => this.CallMethod1(resizable);\n\n    /// <summary>\n    /// Whether the window can be manually resized by user.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsResizableAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Sets whether the window can be moved by user. On Linux does nothing.\n    /// </summary>\n    /// <param name=\"movable\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetMovable(bool movable) => this.CallMethod1(movable);\n\n    /// <summary>\n    /// Whether the window can be moved by user.\n    /// \n    /// On Linux always returns true.\n    /// </summary>\n    /// <returns>On Linux always returns true.</returns>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public Task<bool> IsMovableAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Sets whether the window can be manually minimized by user. On Linux does nothing.\n    /// </summary>\n    /// <param name=\"minimizable\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetMinimizable(bool minimizable) => this.CallMethod1(minimizable);\n\n    /// <summary>\n    /// Whether the window can be manually minimized by user.\n    /// \n    /// On Linux always returns true.\n    /// </summary>\n    /// <returns>On Linux always returns true.</returns>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public Task<bool> IsMinimizableAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Sets whether the window can be manually maximized by user. On Linux does nothing.\n    /// </summary>\n    /// <param name=\"maximizable\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetMaximizable(bool maximizable) => this.CallMethod1(maximizable);\n\n    /// <summary>\n    /// Whether the window can be manually maximized by user.\n    /// \n    /// On Linux always returns true.\n    /// </summary>\n    /// <returns>On Linux always returns true.</returns>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public Task<bool> IsMaximizableAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Sets whether the maximize/zoom window button toggles fullscreen mode or maximizes the window.\n    /// </summary>\n    /// <param name=\"fullscreenable\"></param>\n    public void SetFullScreenable(bool fullscreenable) => this.CallMethod1(fullscreenable);\n\n    /// <summary>\n    /// Whether the maximize/zoom window button toggles fullscreen mode or maximizes the window.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsFullScreenableAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Sets whether the window can be manually closed by user. On Linux does nothing.\n    /// </summary>\n    /// <param name=\"closable\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetClosable(bool closable) => this.CallMethod1(closable);\n\n    /// <summary>\n    /// Whether the window can be manually closed by user.\n    /// \n    /// On Linux always returns true.\n    /// </summary>\n    /// <returns>On Linux always returns true.</returns>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public Task<bool> IsClosableAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Sets whether the window should show always on top of other windows.\n    /// After setting this, the window is still a normal window, not a toolbox\n    /// window which can not be focused on.\n    /// </summary>\n    /// <param name=\"flag\"></param>\n    public void SetAlwaysOnTop(bool flag) => this.CallMethod1(flag);\n\n    /// <summary>\n    /// Sets whether the window should show always on top of other windows.\n    /// After setting this, the window is still a normal window, not a toolbox\n    /// window which can not be focused on.\n    /// </summary>\n    /// <param name=\"flag\"></param>\n    /// <param name=\"level\">Values include normal, floating, torn-off-menu, modal-panel, main-menu,\n    /// status, pop-up-menu and screen-saver. The default is floating.\n    /// See the macOS docs</param>\n    public void SetAlwaysOnTop(bool flag, OnTopLevel level) => this.CallMethod2(flag, level);\n\n    /// <summary>\n    /// Sets whether the window should show always on top of other windows.\n    /// After setting this, the window is still a normal window, not a toolbox\n    /// window which can not be focused on.\n    /// </summary>\n    /// <param name=\"flag\"></param>\n    /// <param name=\"level\">Values include normal, floating, torn-off-menu, modal-panel, main-menu,\n    /// status, pop-up-menu and screen-saver. The default is floating.\n    /// See the macOS docs</param>\n    /// <param name=\"relativeLevel\">The number of layers higher to set this window relative to the given level.\n    /// The default is 0. Note that Apple discourages setting levels higher than 1 above screen-saver.</param>\n    public void SetAlwaysOnTop(bool flag, OnTopLevel level, int relativeLevel) => this.CallMethod3(flag, level, relativeLevel);\n\n    /// <summary>\n    /// Whether the window is always on top of other windows.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsAlwaysOnTopAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Moves window to the center of the screen.\n    /// </summary>\n    public void Center() => this.CallMethod0();\n\n    /// <summary>\n    /// Moves window to x and y.\n    /// </summary>\n    /// <param name=\"x\"></param>\n    /// <param name=\"y\"></param>\n    public void SetPosition(int x, int y)\n    {\n        // Workaround Windows 10 / Electron Bug\n        // https://github.com/electron/electron/issues/4045\n        //if (isWindows10())\n        //{\n        //    x = x - 7;\n        //}\n        this.CallMethod2(x, y);\n    }\n\n    /// <summary>\n    /// Moves window to x and y.\n    /// </summary>\n    /// <param name=\"x\"></param>\n    /// <param name=\"y\"></param>\n    /// <param name=\"animate\"></param>\n    public void SetPosition(int x, int y, bool animate)\n    {\n        // Workaround Windows 10 / Electron Bug\n        // https://github.com/electron/electron/issues/4045\n        //if (isWindows10())\n        //{\n        //    x = x - 7;\n        //}\n\n        this.CallMethod3(x, y, animate);\n    }\n\n    private bool isWindows10()\n    {\n        return RuntimeInformation.OSDescription.Contains(\"Windows 10\");\n    }\n\n    /// <summary>\n    /// Contains the window’s current position.\n    /// </summary>\n    /// <returns></returns>\n    public Task<int[]> GetPositionAsync() => this.InvokeAsync<int[]>();\n\n    /// <summary>\n    /// Changes the title of native window to title.\n    /// </summary>\n    /// <param name=\"title\"></param>\n    public void SetTitle(string title) => this.CallMethod1(title);\n\n    /// <summary>\n    /// The title of the native window.\n    /// \n    /// Note: The title of web page can be different from the title of the native window.\n    /// </summary>\n    /// <returns></returns>\n    public Task<string> GetTitleAsync() => this.InvokeAsync<string>();\n\n    /// <summary>\n    /// Changes the attachment point for sheets on macOS.\n    /// By default, sheets are attached just below the window frame,\n    /// but you may want to display them beneath a HTML-rendered toolbar.\n    /// </summary>\n    /// <param name=\"offsetY\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    public void SetSheetOffset(float offsetY) => this.CallMethod1(offsetY);\n\n    /// <summary>\n    /// Changes the attachment point for sheets on macOS.\n    /// By default, sheets are attached just below the window frame,\n    /// but you may want to display them beneath a HTML-rendered toolbar.\n    /// </summary>\n    /// <param name=\"offsetY\"></param>\n    /// <param name=\"offsetX\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    public void SetSheetOffset(float offsetY, float offsetX) => this.CallMethod2(offsetY, offsetX);\n\n    /// <summary>\n    /// Starts or stops flashing the window to attract user’s attention.\n    /// </summary>\n    /// <param name=\"flag\"></param>\n    public void FlashFrame(bool flag) => this.CallMethod1(flag);\n\n    /// <summary>\n    /// Makes the window not show in the taskbar.\n    /// </summary>\n    /// <param name=\"skip\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetSkipTaskbar(bool skip) => this.CallMethod1(skip);\n\n    /// <summary>\n    /// Enters or leaves the kiosk mode.\n    /// </summary>\n    /// <param name=\"flag\"></param>\n    public void SetKiosk(bool flag) => this.CallMethod1(flag);\n\n    /// <summary>\n    /// Whether the window is in kiosk mode.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsKioskAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Returns the native type of the handle is HWND on Windows, NSView* on macOS, and Window (unsigned long) on Linux.\n    /// </summary>\n    /// <returns>string of the native handle obtained, HWND on Windows, NSView* on macOS, and Window (unsigned long) on Linux.</returns>\n    public Task<string> GetNativeWindowHandle() => this.InvokeAsync<string>();\n\n    /// <summary>\n    /// Sets the pathname of the file the window represents,\n    /// and the icon of the file will show in window’s title bar.\n    /// </summary>\n    /// <param name=\"filename\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    public void SetRepresentedFilename(string filename) => this.CallMethod1(filename);\n\n    /// <summary>\n    /// The pathname of the file the window represents.\n    /// </summary>\n    /// <returns></returns>\n    [SupportedOSPlatform(\"macOS\")]\n    public Task<string> GetRepresentedFilenameAsync() => this.InvokeAsync<string>();\n\n    /// <summary>\n    /// Specifies whether the window’s document has been edited,\n    /// and the icon in title bar will become gray when set to true.\n    /// </summary>\n    /// <param name=\"edited\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    public void SetDocumentEdited(bool edited) => this.CallMethod1(edited);\n\n    /// <summary>\n    /// Whether the window’s document has been edited.\n    /// </summary>\n    /// <returns></returns>\n    [SupportedOSPlatform(\"macOS\")]\n    public Task<bool> IsDocumentEditedAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Focuses the on web view.\n    /// </summary>\n    public void FocusOnWebView() => this.CallMethod0();\n\n    /// <summary>\n    /// Blurs the web view.\n    /// </summary>\n    public void BlurWebView() => this.CallMethod0();\n\n    /// <summary>\n    /// The url can be a remote address (e.g. http://) or\n    /// a path to a local HTML file using the file:// protocol.\n    /// </summary>\n    /// <param name=\"url\"></param>\n    public void LoadURL(string url) => this.CallMethod1(url);\n\n    /// <summary>\n    /// The url can be a remote address (e.g. http://) or\n    /// a path to a local HTML file using the file:// protocol.\n    /// </summary>\n    /// <param name=\"url\"></param>\n    /// <param name=\"options\"></param>\n    public void LoadURL(string url, LoadURLOptions options) => this.CallMethod2(url, options);\n\n    /// <summary>\n    /// Same as webContents.reload.\n    /// </summary>\n    public void Reload() => this.CallMethod0();\n\n    /// <summary>\n    /// Gets the menu items.\n    /// </summary>\n    /// <value>\n    /// The menu items.\n    /// </value>\n    public IReadOnlyCollection<MenuItem> MenuItems\n    {\n        get\n        {\n            return _items.AsReadOnly();\n        }\n    }\n\n    private List<MenuItem> _items = new List<MenuItem>();\n\n    /// <summary>\n    /// Sets the menu as the window’s menu bar,\n    /// setting it to null will remove the menu bar.\n    /// </summary>\n    /// <param name=\"menuItems\"></param>\n    [SupportedOSPlatform(\"Linux\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetMenu(MenuItem[] menuItems)\n    {\n        menuItems.AddMenuItemsId();\n        this.CallMethod1(menuItems);\n        _items.AddRange(menuItems);\n\n        BridgeConnector.Socket.Off(\"windowMenuItemClicked\");\n        BridgeConnector.Socket.On<string>(\"windowMenuItemClicked\", (id) =>\n        {\n            MenuItem menuItem = _items.GetMenuItem(id);\n            menuItem?.Click();\n        });\n    }\n\n    /// <summary>\n    /// Remove the window's menu bar.\n    /// </summary>\n    [SupportedOSPlatform(\"Linux\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void RemoveMenu() => this.CallMethod0();\n\n    /// <summary>\n    /// Sets progress value in progress bar. Valid range is [0, 1.0]. Remove progress\n    /// bar when progress smaler as 0; Change to indeterminate mode when progress bigger as 1. On Linux\n    /// platform, only supports Unity desktop environment, you need to specify the\n    /// .desktop file name to desktopName field in package.json.By default, it will\n    /// assume app.getName().desktop.On Windows, a mode can be passed.Accepted values\n    /// are none, normal, indeterminate, error, and paused. If you call setProgressBar\n    /// without a mode set (but with a value within the valid range), normal will be\n    /// assumed.\n    /// </summary>\n    /// <param name=\"progress\"></param>\n    public void SetProgressBar(double progress) => this.CallMethod1(progress);\n\n    /// <summary>\n    /// Sets progress value in progress bar. Valid range is [0, 1.0]. Remove progress\n    /// bar when progress smaler as 0; Change to indeterminate mode when progress bigger as 1. On Linux\n    /// platform, only supports Unity desktop environment, you need to specify the\n    /// .desktop file name to desktopName field in package.json.By default, it will\n    /// assume app.getName().desktop.On Windows, a mode can be passed.Accepted values\n    /// are none, normal, indeterminate, error, and paused. If you call setProgressBar\n    /// without a mode set (but with a value within the valid range), normal will be\n    /// assumed.\n    /// </summary>\n    /// <param name=\"progress\"></param>\n    /// <param name=\"progressBarOptions\"></param>\n    public void SetProgressBar(double progress, ProgressBarOptions progressBarOptions) =>\n        this.CallMethod2(progress, progressBarOptions);\n\n    /// <summary>\n    /// Sets whether the window should have a shadow. On Windows and Linux does nothing.\n    /// </summary>\n    /// <param name=\"hasShadow\"></param>\n    public void SetHasShadow(bool hasShadow) => this.CallMethod1(hasShadow);\n\n    /// <summary>\n    /// Whether the window has a shadow.\n    /// \n    /// On Windows and Linux always returns true.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> HasShadowAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Gets the thumbar buttons.\n    /// </summary>\n    /// <value>\n    /// The thumbar buttons.\n    /// </value>\n    public IReadOnlyCollection<ThumbarButton> ThumbarButtons\n    {\n        get\n        {\n            return _thumbarButtons.AsReadOnly();\n        }\n    }\n\n    private List<ThumbarButton> _thumbarButtons = new List<ThumbarButton>();\n\n    /// <summary>\n    /// Add a thumbnail toolbar with a specified set of buttons to the thumbnail\n    /// image of a window in a taskbar button layout. Returns a Boolean object\n    /// indicates whether the thumbnail has been added successfully.\n    /// \n    /// The number of buttons in thumbnail toolbar should be no greater than 7 due\n    /// to the limited room.Once you setup the thumbnail toolbar, the toolbar cannot\n    /// be removed due to the platform’s limitation.But you can call the API with an\n    /// empty array to clean the buttons.\n    /// </summary>\n    /// <param name=\"thumbarButtons\"></param>\n    /// <returns>Whether the buttons were added successfully.</returns>\n    [SupportedOSPlatform(\"Windows\")]\n    public Task<bool> SetThumbarButtonsAsync(ThumbarButton[] thumbarButtons)\n    {\n        var tcs = new TaskCompletionSource<bool>();\n\n        BridgeConnector.Socket.Once<bool>(\"browserWindowSetThumbarButtons-completed\", tcs.SetResult);\n\n        thumbarButtons.AddThumbarButtonsId();\n        BridgeConnector.Socket.Emit(\"browserWindowSetThumbarButtons\", Id, thumbarButtons);\n        _thumbarButtons.Clear();\n        _thumbarButtons.AddRange(thumbarButtons);\n\n        BridgeConnector.Socket.Off(\"thumbarButtonClicked\");\n        BridgeConnector.Socket.On<string>(\"thumbarButtonClicked\", (id) =>\n        {\n            ThumbarButton thumbarButton = _thumbarButtons.GetThumbarButton(id);\n            thumbarButton?.Click();\n        });\n\n        return tcs.Task;\n    }\n\n    /// <summary>\n    /// Sets the region of the window to show as the thumbnail image displayed when hovering over\n    /// the window in the taskbar. You can reset the thumbnail to be the entire window by specifying\n    /// an empty region: {x: 0, y: 0, width: 0, height: 0}.\n    /// </summary>\n    /// <param name=\"rectangle\"></param>\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetThumbnailClip(Rectangle rectangle) => this.CallMethod1(rectangle);\n\n    /// <summary>\n    /// Sets the toolTip that is displayed when hovering over the window thumbnail in the taskbar.\n    /// </summary>\n    /// <param name=\"tooltip\"></param>\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetThumbnailToolTip(string tooltip) => this.CallMethod1(tooltip);\n\n    /// <summary>\n    /// Sets the properties for the window’s taskbar button.\n    /// \n    /// Note: relaunchCommand and relaunchDisplayName must always be set together.\n    /// If one of those properties is not set, then neither will be used.\n    /// </summary>\n    /// <param name=\"options\"></param>\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetAppDetails(AppDetailsOptions options) => this.CallMethod1(options);\n\n    /// <summary>\n    /// Same as webContents.showDefinitionForSelection().\n    /// </summary>\n    [SupportedOSPlatform(\"macOS\")]\n    public void ShowDefinitionForSelection() => this.CallMethod0();\n\n    /// <summary>\n    /// Sets whether the window menu bar should hide itself automatically.\n    /// Once set the menu bar will only show when users press the single Alt key.\n    /// \n    /// If the menu bar is already visible, calling setAutoHideMenuBar(true) won’t hide it immediately.\n    /// </summary>\n    /// <param name=\"hide\"></param>\n    [SupportedOSPlatform(\"Linux\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetAutoHideMenuBar(bool hide) => this.CallMethod1(hide);\n\n    /// <summary>\n    /// Whether menu bar automatically hides itself.\n    /// </summary>\n    /// <returns></returns>\n    [SupportedOSPlatform(\"Linux\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public Task<bool> IsMenuBarAutoHideAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Sets whether the menu bar should be visible. If the menu bar is auto-hide,\n    /// users can still bring up the menu bar by pressing the single Alt key.\n    /// </summary>\n    /// <param name=\"visible\"></param>\n    [SupportedOSPlatform(\"Linux\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetMenuBarVisibility(bool visible) => this.CallMethod1(visible);\n\n    /// <summary>\n    /// Whether the menu bar is visible.\n    /// </summary>\n    /// <returns></returns>\n    [SupportedOSPlatform(\"Linux\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public Task<bool> IsMenuBarVisibleAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Sets whether the window should be visible on all workspaces.\n    /// \n    /// Note: This API does nothing on Windows.\n    /// </summary>\n    /// <param name=\"visible\"></param>\n    [SupportedOSPlatform(\"Linux\")]\n    [SupportedOSPlatform(\"macOS\")]\n    public void SetVisibleOnAllWorkspaces(bool visible) => this.CallMethod1(visible);\n\n    /// <summary>\n    /// Whether the window is visible on all workspaces.\n    /// \n    /// Note: This API always returns false on Windows.\n    /// </summary>\n    /// <returns></returns>\n    [SupportedOSPlatform(\"Linux\")]\n    [SupportedOSPlatform(\"macOS\")]\n    public Task<bool> IsVisibleOnAllWorkspacesAsync() => this.InvokeAsync<bool>();\n\n    /// <summary>\n    /// Makes the window ignore all mouse events.\n    /// \n    /// All mouse events happened in this window will be passed to the window\n    /// below this window, but if this window has focus, it will still receive keyboard events.\n    /// </summary>\n    /// <param name=\"ignore\"></param>\n    public void SetIgnoreMouseEvents(bool ignore) => this.CallMethod1(ignore);\n\n    /// <summary>\n    /// Prevents the window contents from being captured by other apps.\n    /// \n    /// On macOS it sets the NSWindow’s sharingType to NSWindowSharingNone.\n    /// On Windows it calls SetWindowDisplayAffinity with WDA_MONITOR.\n    /// </summary>\n    /// <param name=\"enable\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetContentProtection(bool enable) => this.CallMethod1(enable);\n\n    /// <summary>\n    /// Changes whether the window can be focused.\n    /// </summary>\n    /// <param name=\"focusable\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public void SetFocusable(bool focusable) => this.CallMethod1(focusable);\n\n    /// <summary>\n    /// Sets parent as current window’s parent window,\n    /// passing null will turn current window into a top-level window.\n    /// </summary>\n    /// <param name=\"parent\"></param>\n    public void SetParentWindow(BrowserWindow parent)\n    {\n        if (parent == null)\n        {\n            BridgeConnector.Socket.Emit(\"browserWindowSetParentWindow\", Id, null);\n        }\n        else\n        {\n            BridgeConnector.Socket.Emit(\"browserWindowSetParentWindow\", Id, parent);\n        }\n    }\n\n    /// <summary>\n    /// The parent window.\n    /// </summary>\n    /// <returns></returns>\n    public async Task<BrowserWindow> GetParentWindowAsync()\n    {\n        var browserWindowId = await this.InvokeAsync<int>().ConfigureAwait(false);\n        var browserWindow = Electron.WindowManager.BrowserWindows.ToList().Single(x => x.Id == browserWindowId);\n        return browserWindow;\n    }\n\n    /// <summary>\n    /// All child windows.\n    /// </summary>\n    /// <returns></returns>\n    public async Task<List<BrowserWindow>> GetChildWindowsAsync()\n    {\n        var browserWindowIds = await this.InvokeAsync<int[]>().ConfigureAwait(false);\n        var browserWindows = new List<BrowserWindow>();\n\n        foreach (var id in browserWindowIds)\n        {\n            var browserWindow = Electron.WindowManager.BrowserWindows.ToList().Single(x => x.Id == id);\n            browserWindows.Add(browserWindow);\n        }\n\n        return browserWindows;\n    }\n\n    /// <summary>\n    /// Controls whether to hide cursor when typing.\n    /// </summary>\n    /// <param name=\"autoHide\"></param>\n    [SupportedOSPlatform(\"macOS\")]\n    public void SetAutoHideCursor(bool autoHide) => this.CallMethod1(autoHide);\n\n    /// <summary>\n    /// Adds a vibrancy effect to the browser window.\n    /// Passing null or an empty string will remove the vibrancy effect on the window.\n    /// </summary>\n    /// <param name=\"type\">Can be appearance-based, light, dark, titlebar, selection,\n    /// menu, popover, sidebar, medium-light or ultra-dark.\n    /// See the macOS documentation for more details.</param>\n    [SupportedOSPlatform(\"macOS\")]\n    public void SetVibrancy(Vibrancy type) => this.CallMethod1(type);\n\n    /// <summary>\n    /// Render and control web pages.\n    /// </summary>\n    public WebContents WebContents { get; internal set; }\n\n    /// <summary>\n    /// A BrowserView can be used to embed additional web content into a BrowserWindow.\n    /// It is like a child window, except that it is positioned relative to its owning window.\n    /// It is meant to be an alternative to the webview tag.\n    /// </summary>\n    /// <param name=\"browserView\"></param>\n    public void SetBrowserView(BrowserView browserView)\n    {\n        // This message name does not match the default ApiBase naming convention.\n        BridgeConnector.Socket.Emit(\"browserWindow-setBrowserView\", Id, browserView.Id);\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.API/API/Clipboard.cs",
    "content": "using ElectronNET.API.Entities;\nusing ElectronNET.API.Serialization;\nusing System.Runtime.Versioning;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\n// ReSharper disable InconsistentNaming\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Perform copy and paste operations on the system clipboard.\n    /// </summary>\n    public sealed class Clipboard : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n        protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;\n\n        private static Clipboard _clipboard;\n        private static object _syncRoot = new object();\n\n        internal Clipboard()\n        {\n        }\n\n        internal static Clipboard Instance\n        {\n            get\n            {\n                if (_clipboard == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_clipboard == null)\n                        {\n                            _clipboard = new Clipboard();\n                        }\n                    }\n                }\n\n                return _clipboard;\n            }\n        }\n\n        /// <summary>\n        /// Read the content in the clipboard as plain text.\n        /// </summary>\n        /// <param name=\"type\"></param>\n        /// <returns>The content in the clipboard as plain text.</returns>\n        public Task<string> ReadTextAsync(string type = \"\") => this.InvokeAsync<string>(type);\n\n        /// <summary>\n        /// Writes the text into the clipboard as plain text.\n        /// </summary>\n        /// <param name=\"text\"></param>\n        /// <param name=\"type\"></param>\n        public void WriteText(string text, string type = \"\")\n        {\n            BridgeConnector.Socket.Emit(\"clipboard-writeText\", text, type);\n        }\n\n        /// <summary>\n        /// The content in the clipboard as markup.\n        /// </summary>\n        /// <param name=\"type\"></param>\n        /// <returns></returns>\n        public Task<string> ReadHTMLAsync(string type = \"\") => this.InvokeAsync<string>(type);\n\n        /// <summary>\n        /// Writes markup to the clipboard.\n        /// </summary>\n        /// <param name=\"markup\"></param>\n        /// <param name=\"type\"></param>\n        public void WriteHTML(string markup, string type = \"\")\n        {\n            BridgeConnector.Socket.Emit(\"clipboard-writeHTML\", markup, type);\n        }\n\n        /// <summary>\n        /// The content in the clipboard as RTF.\n        /// </summary>\n        /// <param name=\"type\"></param>\n        /// <returns></returns>\n        public Task<string> ReadRTFAsync(string type = \"\") => this.InvokeAsync<string>(type);\n\n        /// <summary>\n        /// Writes the text into the clipboard in RTF.\n        /// </summary>\n        /// <param name=\"text\"></param>\n        /// <param name=\"type\"></param>\n        public void WriteRTF(string text, string type = \"\")\n        {\n            BridgeConnector.Socket.Emit(\"clipboard-writeRTF\", text, type);\n        }\n\n        /// <summary>\n        /// Returns an Object containing title and url keys representing\n        /// the bookmark in the clipboard. The title and url values will\n        /// be empty strings when the bookmark is unavailable.\n        /// </summary>\n        /// <returns></returns>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public Task<ReadBookmark> ReadBookmarkAsync() => this.InvokeAsync<ReadBookmark>();\n\n        /// <summary>\n        /// Writes the title and url into the clipboard as a bookmark.\n        /// \n        /// Note: Most apps on Windows don’t support pasting bookmarks\n        /// into them so you can use clipboard.write to write both a\n        /// bookmark and fallback text to the clipboard.\n        /// </summary>\n        /// <param name=\"title\"></param>\n        /// <param name=\"url\"></param>\n        /// <param name=\"type\"></param>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public void WriteBookmark(string title, string url, string type = \"\")\n        {\n            BridgeConnector.Socket.Emit(\"clipboard-writeBookmark\", title, url, type);\n        }\n\n        /// <summary>\n        /// macOS: The text on the find pasteboard. This method uses synchronous IPC\n        /// when called from the renderer process. The cached value is reread from the\n        /// find pasteboard whenever the application is activated.\n        /// </summary>\n        /// <returns></returns>\n        [SupportedOSPlatform(\"macOS\")]\n        public Task<string> ReadFindTextAsync() => this.InvokeAsync<string>();\n\n        /// <summary>\n        /// macOS: Writes the text into the find pasteboard as plain text. This method uses\n        /// synchronous IPC when called from the renderer process.\n        /// </summary>\n        /// <param name=\"text\"></param>\n        [SupportedOSPlatform(\"macOS\")]\n        public void WriteFindText(string text)\n        {\n            BridgeConnector.Socket.Emit(\"clipboard-writeFindText\", text);\n        }\n\n        /// <summary>\n        /// Clears the clipboard content.\n        /// </summary>\n        /// <param name=\"type\"></param>\n        public void Clear(string type = \"\")\n        {\n            BridgeConnector.Socket.Emit(\"clipboard-clear\", type);\n        }\n\n        /// <summary>\n        /// An array of supported formats for the clipboard type.\n        /// </summary>\n        /// <param name=\"type\"></param>\n        /// <returns></returns>\n        public Task<string[]> AvailableFormatsAsync(string type = \"\") => this.InvokeAsync<string[]>(type);\n\n        /// <summary>\n        /// Writes data to the clipboard.\n        /// </summary>\n        /// <param name=\"data\"></param>\n        /// <param name=\"type\"></param>\n        public void Write(Data data, string type = \"\")\n        {\n            BridgeConnector.Socket.Emit(\"clipboard-write\", data, type);\n        }\n\n        /// <summary>\n        /// Reads an image from the clipboard.\n        /// </summary>\n        /// <param name=\"type\"></param>\n        /// <returns></returns>\n        public Task<NativeImage> ReadImageAsync(string type = \"\") => this.InvokeAsync<NativeImage>(type);\n\n        /// <summary>\n        /// Writes an image to the clipboard.\n        /// </summary>\n        /// <param name=\"image\"></param>\n        /// <param name=\"type\"></param>\n        public void WriteImage(NativeImage image, string type = \"\")\n        {\n            BridgeConnector.Socket.Emit(\"clipboard-writeImage\", JsonSerializer.Serialize(image, ElectronJson.Options), type);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/CommandLine.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Manipulate the command line arguments for your app that Chromium reads.\n    /// </summary>\n    public sealed class CommandLine\n    {\n        internal CommandLine()\n        {\n        }\n\n        internal static CommandLine Instance\n        {\n            get\n            {\n                if (_commandLine == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_commandLine == null)\n                        {\n                            _commandLine = new CommandLine();\n                        }\n                    }\n                }\n\n                return _commandLine;\n            }\n        }\n\n        private static CommandLine _commandLine;\n\n        private static object _syncRoot = new object();\n\n        /// <summary>\n        /// Append a switch (with optional value) to Chromium's command line.\n        /// </summary>\n        /// <param name=\"the_switch\">A command-line switch, without the leading --</param>\n        /// <param name=\"value\">(optional) - A value for the given switch</param>\n        /// <remarks>\n        /// Note: This will not affect process.argv. The intended usage of this function is to control Chromium's behavior.\n        /// </remarks>\n        public void AppendSwitch(string the_switch, string value = \"\")\n        {\n            BridgeConnector.Socket.Emit(\"appCommandLineAppendSwitch\", the_switch, value);\n        }\n\n        /// <summary>\n        /// Append an argument to Chromium's command line. The argument will be quoted correctly. Switches will precede arguments regardless of appending order.\n        ///\n        /// If you're appending an argument like <code>--switch=value</code>, consider using <code>appendSwitch('switch', 'value')</code> instead.\n        /// </summary>\n        /// <param name=\"value\">The argument to append to the command line</param>\n        /// <remarks>\n        /// Note: This will not affect process.argv. The intended usage of this function is to control Chromium's behavior.\n        /// </remarks>\n        public void AppendArgument(string value)\n        {\n            BridgeConnector.Socket.Emit(\"appCommandLineAppendArgument\", value);\n        }\n\n        /// <summary>\n        /// Whether the command-line switch is present.\n        /// </summary>\n        /// <param name=\"switchName\">A command-line switch</param>\n        /// <param name=\"cancellationToken\"></param>\n        /// <returns>Whether the command-line switch is present.</returns>\n        public async Task<bool> HasSwitchAsync(string switchName, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var tcs = new TaskCompletionSource<bool>();\n            using (cancellationToken.Register(() => tcs.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<bool>(\"appCommandLineHasSwitchCompleted\", tcs.SetResult);\n                BridgeConnector.Socket.Emit(\"appCommandLineHasSwitch\", switchName);\n\n                return await tcs.Task.ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// The command-line switch value.\n        /// </summary>\n        /// <param name=\"switchName\">A command-line switch</param>\n        /// <param name=\"cancellationToken\"></param>\n        /// <returns>The command-line switch value.</returns>\n        /// <remarks>\n        /// Note: When the switch is not present or has no value, it returns empty string.\n        /// </remarks>\n        public async Task<string> GetSwitchValueAsync(string switchName, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var tcs = new TaskCompletionSource<string>();\n            using (cancellationToken.Register(() => tcs.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<string>(\"appCommandLineGetSwitchValueCompleted\", tcs.SetResult);\n                BridgeConnector.Socket.Emit(\"appCommandLineGetSwitchValue\", switchName);\n\n                return await tcs.Task.ConfigureAwait(false);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Cookies.cs",
    "content": "using ElectronNET.API.Entities;\nusing ElectronNET.API.Serialization;\nusing System;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Query and modify a session's cookies.\n    /// </summary>\n    public class Cookies\n    {\n        /// <summary>\n        /// Gets the identifier.\n        /// </summary>\n        /// <value>\n        /// The identifier.\n        /// </value>\n        public int Id { get; private set; }\n\n        internal Cookies(int id)\n        {\n            Id = id;\n        }\n\n        /// <summary>\n        /// Emitted when a cookie is changed because it was added, edited, removed, or expired.\n        /// </summary>\n        public event Action<Cookie, CookieChangedCause, bool> OnChanged\n        {\n            add\n            {\n                if (_changed == null)\n                {\n                    BridgeConnector.Socket.On<JsonElement>(\"webContents-session-cookies-changed\" + Id, (args) =>\n                    {\n                        var e = args.EnumerateArray().GetEnumerator();\n                        e.MoveNext();\n                        var cookie = e.Current.Deserialize<Cookie>(ElectronJson.Options);\n                        e.MoveNext();\n                        var cause = e.Current.Deserialize<CookieChangedCause>(ElectronJson.Options);\n                        e.MoveNext();\n                        var removed = e.Current.GetBoolean();\n                        _changed(cookie, cause, removed);\n                    });\n\n                    BridgeConnector.Socket.Emit(\"register-webContents-session-cookies-changed\", Id);\n                }\n\n                _changed += value;\n            }\n            remove\n            {\n                _changed -= value;\n\n                if (_changed == null)\n                {\n                    BridgeConnector.Socket.Off(\"webContents-session-cookies-changed\" + Id);\n                }\n            }\n        }\n\n        private event Action<Cookie, CookieChangedCause, bool> _changed;\n\n\n\n        /// <summary>\n        /// Sends a request to get all cookies matching filter, and resolves a callack with the response.\n        /// </summary>\n        /// <param name=\"filter\">\n        /// </param>\n        /// <returns>A task which resolves an array of cookie objects.</returns>\n        public Task<Cookie[]> GetAsync(CookieFilter filter)\n        {\n            var tcs = new TaskCompletionSource<Cookie[]>();\n            var guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<Cookie[]>(\"webContents-session-cookies-get-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-cookies-get\", Id, filter, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"details\"></param>\n        /// <returns></returns>\n        public Task SetAsync(CookieDetails details)\n        {\n            var tcs = new TaskCompletionSource<object>();\n            var guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<object>(\"webContents-session-cookies-set-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-cookies-set\", Id, details, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Removes the cookies matching url and name\n        /// </summary>\n        /// <param name=\"url\">The URL associated with the cookie.</param>\n        /// <param name=\"name\">The name of cookie to remove.</param>\n        /// <returns>A task which resolves when the cookie has been removed</returns>\n        public Task RemoveAsync(string url, string name)\n        {\n            var tcs = new TaskCompletionSource<object>();\n            var guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<object>(\"webContents-session-cookies-remove-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-cookies-remove\", Id, url, name, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Writes any unwritten cookies data to disk.\n        /// </summary>\n        /// <returns>A task which resolves when the cookie store has been flushed</returns>\n        public Task FlushStoreAsync()\n        {\n            var tcs = new TaskCompletionSource<object>();\n            var guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<object>(\"webContents-session-cookies-flushStore-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-cookies-flushStore\", Id, guid);\n\n            return tcs.Task;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Dialog.cs",
    "content": "using ElectronNET.API.Entities;\nusing System;\nusing System.Runtime.Versioning;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Display native system dialogs for opening and saving files, alerting, etc.\n    /// </summary>\n    public sealed class Dialog\n    {\n        private static Dialog _dialog;\n        private static object _syncRoot = new object();\n\n        internal Dialog()\n        {\n        }\n\n        internal static Dialog Instance\n        {\n            get\n            {\n                if (_dialog == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_dialog == null)\n                        {\n                            _dialog = new Dialog();\n                        }\n                    }\n                }\n\n                return _dialog;\n            }\n        }\n\n        /// <summary>\n        /// Note: On Windows and Linux an open dialog can not be both a file selector\n        /// and a directory selector, so if you set properties to ['openFile', 'openDirectory']\n        /// on these platforms, a directory selector will be shown.\n        /// </summary>\n        /// <param name=\"browserWindow\">The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.</param>\n        /// <param name=\"options\"></param>\n        /// <returns>An array of file paths chosen by the user</returns>\n        public Task<string[]> ShowOpenDialogAsync(BrowserWindow browserWindow, OpenDialogOptions options)\n        {\n            var tcs = new TaskCompletionSource<string[]>();\n            var guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<string[]>(\"showOpenDialogComplete\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"showOpenDialog\",\n                browserWindow,\n                options,\n                guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Dialog for save files.\n        /// </summary>\n        /// <param name=\"browserWindow\">The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.</param>\n        /// <param name=\"options\"></param>\n        /// <returns>Returns String, the path of the file chosen by the user, if a callback is provided it returns an empty string.</returns>\n        public Task<string> ShowSaveDialogAsync(BrowserWindow browserWindow, SaveDialogOptions options)\n        {\n            var tcs = new TaskCompletionSource<string>();\n            var guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<string>(\"showSaveDialogComplete\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"showSaveDialog\",\n                browserWindow,\n                options,\n                guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Shows a message box, it will block the process until the message box is closed.\n        /// It returns the index of the clicked button. The browserWindow argument allows\n        /// the dialog to attach itself to a parent window, making it modal. If a callback\n        /// is passed, the dialog will not block the process.The API call will be\n        /// asynchronous and the result will be passed via callback(response).\n        /// </summary>\n        /// <param name=\"message\"></param>\n        /// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>\n        public async Task<MessageBoxResult> ShowMessageBoxAsync(string message)\n        {\n            return await this.ShowMessageBoxAsync(null, new MessageBoxOptions(message)).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Shows a message box, it will block the process until the message box is closed.\n        /// It returns the index of the clicked button. The browserWindow argument allows\n        /// the dialog to attach itself to a parent window, making it modal. If a callback\n        /// is passed, the dialog will not block the process.The API call will be\n        /// asynchronous and the result will be passed via callback(response).\n        /// </summary>\n        /// <param name=\"messageBoxOptions\"></param>\n        /// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>\n        public async Task<MessageBoxResult> ShowMessageBoxAsync(MessageBoxOptions messageBoxOptions)\n        {\n            return await this.ShowMessageBoxAsync(null, messageBoxOptions).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Shows a message box, it will block the process until the message box is closed.\n        /// It returns the index of the clicked button. If a callback\n        /// is passed, the dialog will not block the process.\n        /// </summary>\n        /// <param name=\"browserWindow\">The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.</param>\n        /// <param name=\"message\"></param>\n        /// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>\n        public async Task<MessageBoxResult> ShowMessageBoxAsync(BrowserWindow browserWindow, string message)\n        {\n            return await this.ShowMessageBoxAsync(browserWindow, new MessageBoxOptions(message)).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Shows a message box, it will block the process until the message box is closed.\n        /// It returns the index of the clicked button. If a callback\n        /// is passed, the dialog will not block the process.\n        /// </summary>\n        /// <param name=\"browserWindow\">The browserWindow argument allows the dialog to attach itself to a parent window, making it modal.</param>\n        /// <param name=\"messageBoxOptions\"></param>\n        /// <returns>The API call will be asynchronous and the result will be passed via MessageBoxResult.</returns>\n        public Task<MessageBoxResult> ShowMessageBoxAsync(BrowserWindow browserWindow, MessageBoxOptions messageBoxOptions)\n        {\n            var tcs = new TaskCompletionSource<MessageBoxResult>();\n            var guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<JsonElement>(\"showMessageBoxComplete\" + guid, (args) =>\n            {\n                // args is [response:int, checkboxChecked:boolean]\n                var arr = args.EnumerateArray();\n                var e = arr.GetEnumerator();\n                e.MoveNext();\n                var response = e.Current.GetInt32();\n                e.MoveNext();\n                var checkbox = e.Current.GetBoolean();\n\n                tcs.SetResult(new MessageBoxResult\n                {\n                    Response = response,\n                    CheckboxChecked = checkbox\n                });\n            });\n\n            if (browserWindow == null)\n            {\n                BridgeConnector.Socket.Emit(\"showMessageBox\", messageBoxOptions, guid);\n            }\n            else\n            {\n                BridgeConnector.Socket.Emit(\"showMessageBox\",\n                    browserWindow,\n                    messageBoxOptions,\n                    guid);\n            }\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Displays a modal dialog that shows an error message.\n        /// \n        /// This API can be called safely before the ready event the app module emits,\n        /// it is usually used to report errors in early stage of startup.If called\n        /// before the app readyevent on Linux, the message will be emitted to stderr,\n        /// and no GUI dialog will appear.\n        /// </summary>\n        /// <param name=\"title\">The title to display in the error box.</param>\n        /// <param name=\"content\">The text content to display in the error box.</param>\n        public void ShowErrorBox(string title, string content)\n        {\n            BridgeConnector.Socket.Emit(\"showErrorBox\", title, content);\n        }\n\n        /// <summary>\n        /// On macOS, this displays a modal dialog that shows a message and certificate information,\n        /// and gives the user the option of trusting/importing the certificate. If you provide a\n        /// browserWindow argument the dialog will be attached to the parent window, making it modal.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        /// <returns></returns>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public Task ShowCertificateTrustDialogAsync(CertificateTrustDialogOptions options)\n        {\n            return ShowCertificateTrustDialogAsync(null, options);\n        }\n\n        /// <summary>\n        /// On macOS, this displays a modal dialog that shows a message and certificate information,\n        /// and gives the user the option of trusting/importing the certificate. If you provide a\n        /// browserWindow argument the dialog will be attached to the parent window, making it modal.\n        /// </summary>\n        /// <param name=\"browserWindow\"></param>\n        /// <param name=\"options\"></param>\n        /// <returns></returns>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public Task ShowCertificateTrustDialogAsync(BrowserWindow browserWindow, CertificateTrustDialogOptions options)\n        {\n            var tcs = new TaskCompletionSource();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once(\"showCertificateTrustDialogComplete\" + guid, () => tcs.SetResult());\n            BridgeConnector.Socket.Emit(\"showCertificateTrustDialog\",\n                browserWindow,\n                options,\n                guid);\n\n            return tcs.Task;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Dock.cs",
    "content": "using System.Collections.Generic;\nusing System.Runtime.Versioning;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing ElectronNET.API.Entities;\nusing ElectronNET.API.Extensions;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Control your app in the macOS dock.\n    /// </summary>\n    [SupportedOSPlatform(\"macOS\")]\n    public sealed class Dock\n    {\n        private static Dock _dock;\n        private static object _syncRoot = new object();\n\n        internal Dock()\n        {\n        }\n\n        internal static Dock Instance\n        {\n            get\n            {\n                if (_dock == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_dock == null)\n                        {\n                            _dock = new Dock();\n                        }\n                    }\n                }\n\n                return _dock;\n            }\n        }\n\n        /// <summary>\n        /// When <see cref=\"DockBounceType.Critical\"/> is passed, the dock icon will bounce until either the application becomes\n        /// active or the request is canceled. When <see cref=\"DockBounceType.Informational\"/> is passed, the dock icon will bounce\n        /// for one second. However, the request remains active until either the application becomes active or the request is canceled.\n        /// <para/>\n        /// Note: This method can only be used while the app is not focused; when the app is focused it will return -1.\n        /// </summary>\n        /// <param name=\"type\">Can be critical or informational. The default is informational.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Return an ID representing the request.</returns>\n        public async Task<int> BounceAsync(DockBounceType type, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var tcs = new TaskCompletionSource<int>();\n            using (cancellationToken.Register(() => tcs.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<int>(\"dock-bounce-completed\", tcs.SetResult);\n                BridgeConnector.Socket.Emit(\"dock-bounce\", type);\n\n                return await tcs.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Cancel the bounce of id.\n        /// </summary>\n        /// <param name=\"id\">Id of the request.</param>\n        public void CancelBounce(int id)\n        {\n            BridgeConnector.Socket.Emit(\"dock-cancelBounce\", id);\n        }\n\n        /// <summary>\n        /// Bounces the Downloads stack if the filePath is inside the Downloads folder.\n        /// </summary>\n        /// <param name=\"filePath\"></param>\n        public void DownloadFinished(string filePath)\n        {\n            BridgeConnector.Socket.Emit(\"dock-downloadFinished\", filePath);\n        }\n\n        /// <summary>\n        /// Sets the string to be displayed in the dock’s badging area.\n        /// </summary>\n        /// <param name=\"text\"></param>\n        public void SetBadge(string text)\n        {\n            BridgeConnector.Socket.Emit(\"dock-setBadge\", text);\n        }\n\n        /// <summary>\n        /// Gets the string to be displayed in the dock’s badging area.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>The badge string of the dock.</returns>\n        public async Task<string> GetBadgeAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var tcs = new TaskCompletionSource<string>();\n            using (cancellationToken.Register(() => tcs.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<string>(\"dock-getBadge-completed\", tcs.SetResult);\n                BridgeConnector.Socket.Emit(\"dock-getBadge\");\n\n                return await tcs.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Hides the dock icon.\n        /// </summary>\n        public void Hide()\n        {\n            BridgeConnector.Socket.Emit(\"dock-hide\");\n        }\n\n        /// <summary>\n        /// Shows the dock icon.\n        /// </summary>\n        public void Show()\n        {\n            BridgeConnector.Socket.Emit(\"dock-show\");\n        }\n\n        /// <summary>\n        /// Whether the dock icon is visible. The app.dock.show() call is asynchronous\n        /// so this method might not return true immediately after that call.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>Whether the dock icon is visible.</returns>\n        public async Task<bool> IsVisibleAsync(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var tcs = new TaskCompletionSource<bool>();\n            using (cancellationToken.Register(() => tcs.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<bool>(\"dock-isVisible-completed\", tcs.SetResult);\n                BridgeConnector.Socket.Emit(\"dock-isVisible\");\n\n                return await tcs.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Gets the dock menu items.\n        /// </summary>\n        /// <value>\n        /// The menu items.\n        /// </value>\n        public IReadOnlyCollection<MenuItem> MenuItems\n        {\n            get\n            {\n                return _items.AsReadOnly();\n            }\n        }\n\n        private List<MenuItem> _items = new List<MenuItem>();\n\n        /// <summary>\n        /// Sets the application's dock menu.\n        /// </summary>\n        public void SetMenu(MenuItem[] menuItems)\n        {\n            menuItems.AddMenuItemsId();\n            BridgeConnector.Socket.Emit(\"dock-setMenu\", new[] { menuItems });\n            _items.AddRange(menuItems);\n\n            BridgeConnector.Socket.Off(\"dockMenuItemClicked\");\n            BridgeConnector.Socket.On<string>(\"dockMenuItemClicked\", (id) =>\n            {\n                MenuItem menuItem = _items.GetMenuItem(id);\n                menuItem?.Click();\n            });\n        }\n\n        /// <summary>\n        /// TODO: Menu (macOS) still to be implemented\n        /// Gets the application's dock menu.\n        /// </summary>\n        public async Task<Menu> GetMenu(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var tcs = new TaskCompletionSource<Menu>();\n            using (cancellationToken.Register(() => tcs.TrySetCanceled()))\n            {\n                BridgeConnector.Socket.Once<Menu>(\"dock-getMenu-completed\", tcs.SetResult);\n                BridgeConnector.Socket.Emit(\"dock-getMenu\");\n\n                return await tcs.Task\n                    .ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        /// Sets the image associated with this dock icon.\n        /// </summary>\n        /// <param name=\"image\"></param>\n        public void SetIcon(string image)\n        {\n            BridgeConnector.Socket.Emit(\"dock-setIcon\", image);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Electron.cs",
    "content": "﻿namespace ElectronNET.API\n{\n    /// <summary>\n    /// The Electron.NET API\n    /// </summary>\n    public static class Electron\n    {\n        /// <summary>\n        /// Communicate asynchronously from the main process to renderer processes.\n        /// </summary>\n        public static IpcMain IpcMain\n        {\n            get\n            {\n                return IpcMain.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Control your application's event lifecycle.\n        /// </summary>\n        public static App App\n        {\n            get\n            {\n                return App.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Enable apps to automatically update themselves. Based on electron-updater.\n        /// </summary>\n        public static AutoUpdater AutoUpdater\n        {\n            get\n            {\n                return AutoUpdater.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Control your windows.\n        /// </summary>\n        public static WindowManager WindowManager\n        {\n            get\n            {\n                return WindowManager.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Create native application menus and context menus.\n        /// </summary>\n        public static Menu Menu\n        {\n            get\n            {\n                return Menu.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Display native system dialogs for opening and saving files, alerting, etc.\n        /// </summary>\n        public static Dialog Dialog\n        {\n            get\n            {\n                return Dialog.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Create OS desktop notifications\n        /// </summary>\n        public static Notification Notification\n        {\n            get\n            {\n                return Notification.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Add icons and context menus to the system’s notification area.\n        /// </summary>\n        public static Tray Tray\n        {\n            get\n            {\n                return Tray.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Detect keyboard events when the application does not have keyboard focus.\n        /// </summary>\n        public static GlobalShortcut GlobalShortcut\n        {\n            get\n            {\n                return GlobalShortcut.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Manage files and URLs using their default applications.\n        /// </summary>\n        public static Shell Shell\n        {\n            get\n            {\n                return Shell.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Retrieve information about screen size, displays, cursor position, etc.\n        /// </summary>\n        public static Screen Screen\n        {\n            get\n            {\n                return Screen.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Perform copy and paste operations on the system clipboard.\n        /// </summary>\n        public static Clipboard Clipboard\n        {\n            get\n            {\n                return Clipboard.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Allows you to execute native JavaScript/TypeScript code from the host process.\n        /// \n        /// It is only possible if the Electron.NET CLI has previously added an\n        /// ElectronHostHook directory:\n        /// <c>electronize add HostHook</c>\n        /// </summary>\n        public static HostHook HostHook\n        {\n            get\n            {\n                return HostHook.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Allows you to execute native Lock and Unlock process.\n        /// </summary>\n        public static PowerMonitor PowerMonitor\n        {\n            get\n            {\n                return PowerMonitor.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Read and respond to changes in Chromium's native color theme.\n        /// </summary>\n        public static NativeTheme NativeTheme\n        {\n            get\n            {\n                return NativeTheme.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Control your app in the macOS dock.\n        /// </summary>\n        public static Dock Dock\n        {\n            get\n            {\n                return Dock.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Electeon extensions to the Nodejs process object.\n        /// </summary>\n        public static Process Process\n        {\n            get\n            {\n                return Process.Instance;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/AboutPanelOptions.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// About panel options.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class AboutPanelOptions\n    {\n        /// <summary>\n        /// The app's name.\n        /// </summary>\n        public string ApplicationName { get; set; }\n\n        /// <summary>\n        /// The app's version.\n        /// </summary>\n        public string ApplicationVersion { get; set; }\n\n        /// <summary>\n        /// Copyright information.\n        /// </summary>\n        public string Copyright { get; set; }\n\n        /// <summary>\n        /// The app's build version number (macOS).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string Version { get; set; }\n\n        /// <summary>\n        /// Credit information (macOS, Windows).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [SupportedOSPlatform(\"windows\")]\n        public string Credits { get; set; }\n\n        /// <summary>\n        /// List of app authors (Linux).\n        /// </summary>\n        [SupportedOSPlatform(\"linux\")]\n        public string[] Authors { get; set; }\n\n        /// <summary>\n        /// The app's website (Linux).\n        /// </summary>\n        [SupportedOSPlatform(\"linux\")]\n        public string Website { get; set; }\n\n        /// <summary>\n        /// Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as 64x64 pixels while retaining aspect ratio. On Windows, a 48x48 PNG will result in the best visual quality.\n        /// </summary>\n        [SupportedOSPlatform(\"linux\")]\n        [SupportedOSPlatform(\"windows\")]\n        public string IconPath { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/AddRepresentationOptions.cs",
    "content": "using System.Text.Json.Serialization;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class AddRepresentationOptions\n    {\n        /// <summary>\n        /// Gets or sets the width in pixels. Defaults to 0. Required if a bitmap buffer is specified as <see cref=\"Buffer\"/>.\n        /// </summary>\n        public int? Width { get; set; }\n\n        /// <summary>\n        /// Gets or sets the height in pixels. Defaults to 0. Required if a bitmap buffer is specified as <see cref=\"Buffer\"/>.\n        /// </summary>\n        public int? Height { get; set; }\n\n        /// <summary>\n        /// Gets or sets the image scale factor. Defaults to 1.0.\n        /// </summary>\n        public float ScaleFactor { get; set; } = 1.0f;\n\n        /// <summary>\n        /// Gets or sets the buffer containing the raw image data.\n        /// </summary>\n        public byte[] Buffer { get; set; }\n\n        /// <summary>\n        /// Gets or sets the data URL containing a base 64 encoded PNG or JPEG image.\n        /// </summary>\n        public string DataUrl { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/AppDetailsOptions.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"windows\")]\n    public class AppDetailsOptions\n    {\n        /// <summary>\n        /// Window's App User Model ID. It has to be set, otherwise the other options will have no effect.\n        /// </summary>\n        public string AppId { get; set; }\n\n        /// <summary>\n        /// Window's relaunch icon resource path.\n        /// </summary>\n        public string AppIconPath { get; set; }\n\n        /// <summary>\n        /// Index of the icon in <see cref=\"AppIconPath\"/>. Ignored when <see cref=\"AppIconPath\"/> is not set. Default is 0.\n        /// </summary>\n        public int AppIconIndex { get; set; }\n\n        /// <summary>\n        /// Window's relaunch command.\n        /// </summary>\n        public string RelaunchCommand { get; set; }\n\n        /// <summary>\n        /// Window's relaunch display name.\n        /// </summary>\n        public string RelaunchDisplayName { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/AutoResizeOptions.cs",
    "content": "﻿using System.ComponentModel;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class AutoResizeOptions\n    {\n        /// <summary>\n        /// If `true`, the view's width will grow and shrink together with the window.\n        /// `false` by default.\n        /// </summary>\n        [DefaultValue(false)]\n        public bool Width { get; set; } = false;\n\n        /// <summary>\n        /// If `true`, the view's height will grow and shrink together with the window.\n        /// `false` by default.\n        /// </summary>\n        [DefaultValue(false)]\n        public bool Height { get; set; } = false;\n\n        /// <summary>\n        /// If `true`, the view's x position and width will grow and shrink proportionally\n        /// with the window. `false` by default.\n        /// </summary>\n        [DefaultValue(false)]\n        public bool Horizontal { get; set; } = false;\n\n        /// <summary>\n        /// If `true`, the view's y position and height will grow and shrink proportionally\n        /// with the window. `false` by default.\n        /// </summary>\n        [DefaultValue(false)]\n        public bool Vertical { get; set; } = false;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/BitmapOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class BitmapOptions\n    {\n        /// <summary>\n        /// The image scale factor. Defaults to 1.0.\n        /// </summary>\n        public float ScaleFactor { get; set; } = 1.0f;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Blob.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class Blob : IPostData\n    {\n        /// <summary>\n        /// The object represents a Blob\n        /// </summary>\n        public string Type { get; } = \"blob\";\n\n        /// <summary>\n        /// The UUID of the Blob being uploaded\n        /// </summary>\n        public string BlobUUID { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/BlockMapDataHolder.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public class BlockMapDataHolder\n    {\n        /// <summary>\n        /// The file size. Used to verify downloaded size (save one HTTP request to get length).\n        /// Also used when block map data is embedded into the file(appimage, windows web installer package).\n        /// </summary>\n        public double Size { get; set; }\n\n        /// <summary>\n        /// The block map file size. Used when block map data is embedded into the file (appimage, windows web installer package).\n        /// This information can be obtained from the file itself, but it requires additional HTTP request,\n        /// so, to reduce request count, block map size is specified in the update metadata too.\n        /// </summary>\n        public double BlockMapSize { get; set; }\n\n        /// <summary>\n        /// The file checksum.\n        /// </summary>\n        public string Sha512 { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public bool IsAdminRightsRequired { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/BrowserViewConstructorOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class BrowserViewConstructorOptions\n    {\n        /// <summary>\n        /// Gets or sets the web preferences for the view (see WebPreferences).\n        /// </summary>\n        public WebPreferences WebPreferences { get; set; }\n\n        /// <summary>\n        /// Gets or sets a proxy to use on creation in the format host:port.\n        /// The proxy can be alternatively set using the BrowserView.WebContents.SetProxyAsync function.\n        /// </summary>\n        /// <remarks>This is custom shortcut. Not part of the Electron API.</remarks>\n        public string Proxy { get; set; }\n\n        /// <summary>\n        /// Gets or sets the credentials of the proxy in the format username:password.\n        /// These will only be used if the Proxy field is also set.\n        /// </summary>\n        /// <remarks>This is custom shortcut. Not part of the Electron API.</remarks>\n        public string ProxyCredentials { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/BrowserWindowOptions.cs",
    "content": "using ElectronNET.Converter;\nusing System.ComponentModel;\nusing System.Text.Json.Serialization;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public class BrowserWindowOptions\n    {\n        /// <summary>\n        /// Window's width in pixels. Default is 800.\n        /// </summary>\n        public int Width { get; set; } = 800;\n\n        /// <summary>\n        /// Window's height in pixels. Default is 600.\n        /// </summary>\n        public int Height { get; set; } = 600;\n\n        /// <summary>\n        /// ( if y is used) Window's left offset from screen. Default is to center the\n        /// window.\n        /// </summary>\n        public int? X { get; set; }\n\n        /// <summary>\n        /// ( if x is used) Window's top offset from screen. Default is to center the\n        /// window.\n        /// </summary>\n        public int? Y { get; set; }\n\n        /// <summary>\n        /// The width and height would be used as web page's size, which means the actual\n        /// window's size will include window frame's size and be slightly larger. Default\n        /// is false.\n        /// </summary>\n        public bool UseContentSize { get; set; }\n\n        /// <summary>\n        /// Show window in the center of the screen.\n        /// </summary>\n        public bool Center { get; set; }\n\n        /// <summary>\n        /// Window's minimum width. Default is 0.\n        /// </summary>\n        public int MinWidth { get; set; }\n\n        /// <summary>\n        /// Window's minimum height. Default is 0.\n        /// </summary>\n        public int MinHeight { get; set; }\n\n        /// <summary>\n        /// Window's maximum width. Default is no limit.\n        /// </summary>\n        public int MaxWidth { get; set; }\n\n        /// <summary>\n        /// Window's maximum height. Default is no limit.\n        /// </summary>\n        public int MaxHeight { get; set; }\n\n        /// <summary>\n        /// Whether window is resizable. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Resizable { get; set; } = true;\n\n        /// <summary>\n        /// Whether window is movable. This is not implemented on Linux. Default is true.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [SupportedOSPlatform(\"windows\")]\n        [DefaultValue(true)]\n        public bool Movable { get; set; } = true;\n\n        /// <summary>\n        /// Whether window is minimizable. This is not implemented on Linux. Default is true.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [SupportedOSPlatform(\"windows\")]\n        [DefaultValue(true)]\n        public bool Minimizable { get; set; } = true;\n\n        /// <summary>\n        /// Whether window is maximizable. This is not implemented on Linux. Default is true.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [SupportedOSPlatform(\"windows\")]\n        [DefaultValue(true)]\n        public bool Maximizable { get; set; } = true;\n\n        /// <summary>\n        /// Whether window is closable. This is not implemented on Linux. Default is true.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [SupportedOSPlatform(\"windows\")]\n        [DefaultValue(true)]\n        public bool Closable { get; set; } = true;\n\n        /// <summary>\n        /// Whether the window can be focused. Default is true. On Windows setting\n        /// focusable: false also implies setting skipTaskbar: true. On Linux setting\n        /// focusable: false makes the window stop interacting with wm, so the window will\n        /// always stay on top in all workspaces.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Focusable { get; set; } = true;\n\n        /// <summary>\n        /// Whether the window should always stay on top of other windows. Default is false.\n        /// </summary>\n        public bool AlwaysOnTop { get; set; }\n\n        /// <summary>\n        /// Whether the window should show in fullscreen. When explicitly set to false the\n        /// fullscreen button will be hidden or disabled on macOS.Default is false.\n        /// </summary>\n        public bool Fullscreen { get; set; }\n\n        /// <summary>\n        /// Whether the window can be put into fullscreen mode. On macOS, also whether the\n        /// maximize/zoom button should toggle full screen mode or maximize window. Default\n        /// is true (Electron default).\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Fullscreenable { get; set; } = true; // FIX: previously defaulted to false in C#\n\n        /// <summary>\n        /// Whether to show the window in taskbar. Default is false.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [SupportedOSPlatform(\"windows\")]\n        public bool SkipTaskbar { get; set; }\n\n        /// <summary>\n        /// Determines if Blazor is used. Will disable \"module\" and \"process\" globals. Default is false.\n        /// </summary>\n        public bool IsRunningBlazor { get; set; }\n\n        /// <summary>\n        /// The kiosk mode. Default is false.\n        /// </summary>\n        public bool Kiosk { get; set; }\n\n        /// <summary>\n        /// Default window title. Default is \"Electron.NET\".\n        /// </summary>\n        public string Title { get; set; } = \"Electron.NET\";\n\n        /// <summary>\n        /// The window icon. Can be a NativeImage or a string path. On Windows it is recommended to use ICO icons; when undefined, the executable's icon will be used.\n        /// </summary>\n        public string Icon { get; set; }\n\n        /// <summary>\n        /// Whether window should be shown when created. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Show { get; set; } = true;\n\n        /// <summary>\n        /// Specify false to create a frameless window. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Frame { get; set; } = true;\n\n        /// <summary>\n        /// Whether this is a modal window. This only works when the window is a child\n        /// window.Default is false.\n        /// </summary>\n        public bool Modal { get; set; }\n\n        /// <summary>\n        /// Whether the web view accepts a single mouse-down event that simultaneously\n        /// activates the window.Default is false.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool AcceptFirstMouse { get; set; }\n\n        /// <summary>\n        /// Whether to hide cursor when typing. Default is false.\n        /// </summary>\n        public bool DisableAutoHideCursor { get; set; }\n\n        /// <summary>\n        /// Auto hide the menu bar unless the Alt key is pressed. Default is false.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        [SupportedOSPlatform(\"linux\")]\n        public bool AutoHideMenuBar { get; set; }\n\n        /// <summary>\n        /// Enable the window to be resized larger than screen. Default is false.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool EnableLargerThanScreen { get; set; }\n\n        /// <summary>\n        /// The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha in #AARRGGBB format is supported if transparent is set to true. Default is #FFF (white).\n        /// </summary>\n        public string BackgroundColor { get; set; }\n\n        /// <summary>\n        /// Initial opacity of the window, between 0.0 (fully transparent) and 1.0 (fully opaque). Only implemented on Windows and macOS.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        [SupportedOSPlatform(\"macos\")]\n        public double? Opacity { get; set; }\n\n        /// <summary>\n        /// Whether window should have a shadow. Default is true.\n        /// </summary>\n        public bool HasShadow { get; set; }\n\n        /// <summary>\n        /// Forces using dark theme for the window, only works on some GTK+3 desktop environments. Default is false.\n        /// </summary>\n        public bool DarkTheme { get; set; }\n\n        /// <summary>\n        /// Makes the window transparent. Default is false.\n        /// </summary>\n        public bool Transparent { get; set; }\n\n        /// <summary>\n        /// The type of window, default is normal window.\n        /// </summary>\n        public string Type { get; set; }\n\n        /// <summary>\n        /// The style of window title bar. Default is default. Possible values are:\n        /// 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover'\n        /// </summary>\n        public TitleBarStyle TitleBarStyle { get; set; }\n\n        /// <summary>\n        /// Set a custom position for the traffic light buttons in frameless windows (macOS).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public Point TrafficLightPosition { get; set; }\n\n        /// <summary>\n        /// Configures the window's title bar overlay when using a frameless window.\n        /// Can be either:\n        /// - false: No title bar overlay.\n        /// - true: Enables the default title bar overlay.\n        /// - An object defining custom overlay options (such as height, color, etc.).\n        /// \n        /// Default is false.\n        /// </summary>\n        [JsonConverter(typeof(TitleBarOverlayConverter))]\n        public TitleBarOverlay TitleBarOverlay { get; set; }\n\n        /// <summary>\n        /// Shows the title in the title bar in full screen mode on macOS for all titleBarStyle options. Default is false.\n        /// </summary>\n        /// <remarks>Not documented by MCP base-window-options / browser-window-options.</remarks>\n        public bool FullscreenWindowTitle { get; set; }\n\n        /// <summary>\n        /// Use WS_THICKFRAME style for frameless windows on Windows, which adds standard\n        /// window frame.Setting it to false will remove window shadow and window\n        /// animations. Default is true.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        [DefaultValue(true)]\n        public bool ThickFrame { get; set; } = true;\n\n        /// <summary>\n        /// Whether frameless window should have rounded corners. Default is true. Setting this\n        /// property to false will prevent the window from being fullscreenable on macOS. On\n        /// Windows versions older than Windows 11 Build 22000 this property has no effect, and\n        /// frameless windows will not have rounded corners.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [SupportedOSPlatform(\"windows\")]\n        [DefaultValue(true)]\n        public bool RoundedCorners { get; set; } = true;\n\n        /// <summary>\n        /// Add a type of vibrancy effect to the window, only on macOS. Can be\n        /// appearance-based, titlebar, selection, menu, popover, sidebar, header, sheet,\n        /// window, hud, fullscreen-ui, tooltip, content, under-window, or under-page.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public Vibrancy Vibrancy { get; set; }\n\n        /// <summary>\n        /// Controls the behavior on macOS when option-clicking the green stoplight button\n        /// on the toolbar or by clicking the Window > Zoom menu item.If true, the window\n        /// will grow to the preferred width of the web page when zoomed, false will cause\n        /// it to zoom to the width of the screen.This will also affect the behavior when\n        /// calling maximize() directly.Default is false.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool ZoomToPageWidth { get; set; }\n\n        /// <summary>\n        /// Tab group name, allows opening the window as a native tab on macOS 10.12+.\n        /// Windows with the same tabbing identifier will be grouped together.This also\n        /// adds a native new tab button to your window's tab bar and allows your app and\n        /// window to receive the new-window-for-tab event.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string TabbingIdentifier { get; set; }\n\n        /// <summary>\n        /// Settings of web page's features.\n        /// </summary>\n        public WebPreferences WebPreferences { get; set; }\n\n        /// <summary>\n        /// A proxy to set on creation in the format host:port.\n        /// The proxy can be alternatively set using the BrowserWindow.WebContents.SetProxyAsync function.\n        /// </summary>\n        /// <remarks>Not documented by MCP base-window-options / browser-window-options.</remarks>\n        public string Proxy { get; set; }\n\n        /// <summary>\n        /// The credentials of the Proxy in the format username:password.\n        /// These will only be used if the Proxy field is also set.\n        /// </summary>\n        /// <remarks>Not documented by MCP base-window-options / browser-window-options.</remarks>\n        public string ProxyCredentials { get; set; }\n\n        /// <summary>\n        /// Gets or sets whether to use pre-Lion fullscreen on macOS. Default is false.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool SimpleFullscreen { get; set; }\n\n        /// <summary>\n        /// Gets or sets whether the window should be hidden when the user toggles into mission control (macOS).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool HiddenInMissionControl { get; set; }\n\n        /// <summary>\n        /// Gets or sets how the material appearance should reflect window activity state on macOS. Must be used with the vibrancy property.\n        /// Possible values: 'followWindow' (default), 'active', 'inactive'.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string VisualEffectState { get; set; }\n\n        /// <summary>\n        /// Gets or sets the system-drawn background material on Windows. Can be 'auto', 'none', 'mica', 'acrylic' or 'tabbed'.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string BackgroundMaterial { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/CPUUsage.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class CPUUsage\n    {\n        /// <summary>\n        /// Percentage of CPU used since the last call to getCPUUsage. First call returns 0.\n        /// </summary>\n        public double PercentCPUUsage { get; set; }\n\n        /// <summary>\n        /// Total seconds of CPU time used since process startup, if available.\n        /// </summary>\n        public double? CumulativeCPUUsage { get; set; }\n\n        /// <summary>\n        /// The number of average idle CPU wakeups per second since the last call to\n        /// getCPUUsage. First call returns 0. Will always return 0 on Windows.\n        /// </summary>\n        public double IdleWakeupsPerSecond { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Certificate.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class Certificate\n    {\n        /// <summary>\n        /// PEM encoded data\n        /// </summary>\n        public string Data { get; set; }\n\n        /// <summary>\n        /// Fingerprint of the certificate\n        /// </summary>\n        public string Fingerprint { get; set; }\n\n        /// <summary>\n        /// Issuer principal\n        /// </summary>\n        public CertificatePrincipal Issuer { get; set; }\n\n        /// <summary>\n        /// Issuer certificate (if not self-signed)\n        /// </summary>\n        public Certificate IssuerCert { get; set; }\n\n        /// <summary>\n        /// Issuer's Common Name\n        /// </summary>\n        public string IssuerName { get; set; }\n\n        /// <summary>\n        /// Hex value represented string\n        /// </summary>\n        public string SerialNumber { get; set; }\n\n        /// <summary>\n        /// Subject principal\n        /// </summary>\n        public CertificatePrincipal Subject { get; set; }\n\n        /// <summary>\n        /// Subject's Common Name\n        /// </summary>\n        public string SubjectName { get; set; }\n\n        /// <summary>\n        /// End date of the certificate being valid in seconds\n        /// </summary>\n        public int ValidExpiry { get; set; }\n\n        /// <summary>\n        /// Start date of the certificate being valid in seconds\n        /// </summary>\n        public int ValidStart { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/CertificatePrincipal.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class CertificatePrincipal\n    {\n        /// <summary>\n        /// Common Name\n        /// </summary>\n        public string CommonName { get; set; }\n\n        /// <summary>\n        /// Country or region\n        /// </summary>\n        public string Country { get; set; }\n\n        /// <summary>\n        /// Locality\n        /// </summary>\n        public string Locality { get; set; }\n\n        /// <summary>\n        /// Organization names\n        /// </summary>\n        public string[] Organizations { get; set; }\n\n        /// <summary>\n        /// Organization Unit names\n        /// </summary>\n        public string[] OrganizationUnits { get; set; }\n\n        /// <summary>\n        /// State or province\n        /// </summary>\n        public string State { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/CertificateTrustDialogOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class CertificateTrustDialogOptions\n    {\n        /// <summary>\n        /// The certificate to trust/import.\n        /// </summary>\n        public Certificate Certificate { get; set; }\n\n        /// <summary>\n        /// The message to display to the user.\n        /// </summary>\n        public string Message { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ChromeExtensionInfo.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Provide metadata about the current loaded Chrome extension\n    /// </summary>\n    /// <yremarks>Project-specific: no matching Electron structure found in MCP docs (electronjs).</yremarks>\n    public class ChromeExtensionInfo\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ChromeExtensionInfo\"/> class.\n        /// </summary>\n        /// <param name=\"name\">The name of the Chrome extension.</param>\n        /// <param name=\"version\">The version of the Chrome extension.</param>\n        public ChromeExtensionInfo(string name, string version)\n        {\n            Name = name;\n            Version = version;\n        }\n\n        /// <summary>\n        /// Name of the Chrome extension\n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Version of the Chrome extension\n        /// </summary>\n        public string Version { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ClearStorageDataOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class ClearStorageDataOptions\n    {\n        /// <summary>\n        /// Should follow window.location.origin’s representation scheme://host:port.\n        /// </summary>\n        public string Origin { get; set; }\n\n        /// <summary>\n        /// The types of storages to clear. Can contain: cookies, filesystem, indexdb,\n        /// localstorage, shadercache, websql, serviceworkers, cachestorage.\n        /// If not specified, all storage types are cleared.\n        /// </summary>\n        public string[] Storages { get; set; }\n\n        /// <summary>\n        /// The types of quotas to clear. Can contain: temporary. If not specified,\n        /// all quotas are cleared. The <c>quotas</c> option is deprecated;\n        /// \"temporary\" is the only remaining supported quota type.\n        /// </summary>\n        public string[] Quotas { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Cookie.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Cookie structure as used by Electron session.cookies APIs.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class Cookie\n    {\n        /// <summary>\n        /// Gets or sets the name of the cookie.\n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Gets or sets the value of the cookie.\n        /// </summary>\n        public string Value { get; set; }\n\n        /// <summary>\n        /// Gets or sets the domain of the cookie; this will be normalized with a preceding dot so that it's also valid for subdomains.\n        /// </summary>\n        public string Domain { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the cookie is a host-only cookie; this will only be true if no domain was passed.\n        /// </summary>\n        public bool? HostOnly { get; set; }\n\n        /// <summary>\n        /// Gets or sets the path of the cookie.\n        /// </summary>\n        public string Path { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the cookie is marked as secure.\n        /// </summary>\n        public bool? Secure { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the cookie is marked as HTTP only.\n        /// </summary>\n        public bool? HttpOnly { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the cookie is a session cookie or a persistent cookie with an expiration date.\n        /// </summary>\n        public bool? Session { get; set; }\n\n        /// <summary>\n        /// Gets or sets the expiration date of the cookie as the number of seconds since the UNIX epoch. Not provided for session cookies.\n        /// </summary>\n        public double? ExpirationDate { get; set; }\n\n        /// <summary>\n        /// Gets or sets the SameSite policy applied to this cookie. Can be \"unspecified\", \"no_restriction\", \"lax\" or \"strict\".\n        /// </summary>\n        public string SameSite { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/CookieChangedCause.cs",
    "content": "namespace ElectronNET.API.Entities\n{\n    using System.Text.Json.Serialization;\n\n    /// <summary>\n    /// The cause of the cookie change (per Electron Cookies 'changed' event).\n    /// </summary>\n    public enum CookieChangedCause\n    {\n        /// <summary>\n        /// The cookie was changed directly by a consumer's action.\n        /// </summary>\n        @explicit,\n\n        /// <summary>\n        /// The cookie was automatically removed due to an insert operation that overwrote it.\n        /// </summary>\n        overwrite,\n\n        /// <summary>\n        /// The cookie was automatically removed as it expired.\n        /// </summary>\n        expired,\n\n        /// <summary>\n        /// The cookie was automatically evicted during garbage collection.\n        /// </summary>\n        evicted,\n\n        /// <summary>\n        /// The cookie was overwritten with an already-expired expiration date.\n        /// </summary>\n        [JsonPropertyName(\"expired_overwrite\")]\n        expiredOverwrite\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/CookieDetails.cs",
    "content": "﻿using System.ComponentModel;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class CookieDetails\n    {\n        /// <summary>\n        /// Gets or sets the URL to associate the cookie with. The operation will be rejected if the URL is invalid.\n        /// </summary>\n        public string Url { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name of the cookie. Empty by default if omitted.\n        /// </summary>\n        [DefaultValue(\"\")]\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Gets or sets the value of the cookie. Empty by default if omitted.\n        /// </summary>\n        [DefaultValue(\"\")]\n        public string Value { get; set; }\n\n        /// <summary>\n        /// Gets or sets the domain of the cookie; this will be normalized with a preceding dot so that it's also valid for subdomains. Empty by default if omitted.\n        /// </summary>\n        [DefaultValue(\"\")]\n        public string Domain { get; set; }\n\n        /// <summary>\n        /// Gets or sets the path of the cookie. Empty by default if omitted.\n        /// </summary>\n        [DefaultValue(\"\")]\n        public string Path { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the cookie should be marked as secure. Defaults to false unless the SameSite policy is set to <c>no_restriction</c> (SameSite=None).\n        /// </summary>\n        [DefaultValue(false)]\n        public bool Secure { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the cookie should be marked as HTTP only. Defaults to false.\n        /// </summary>\n        [DefaultValue(false)]\n        public bool HttpOnly { get; set; }\n\n        /// <summary>\n        /// Gets or sets the expiration date of the cookie as the number of seconds since the UNIX epoch. If omitted, the cookie becomes a session cookie and will not be retained between sessions.\n        /// </summary>\n        [DefaultValue(0)]\n        public double ExpirationDate { get; set; }\n\n        /// <summary>\n        /// Gets or sets the SameSite policy to apply to this cookie. Can be \"unspecified\", \"no_restriction\", \"lax\" or \"strict\". Default is \"lax\".\n        /// </summary>\n        public string SameSite { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/CookieFilter.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class CookieFilter\n    {\n        /// <summary>\n        /// (optional) - Retrieves cookies which are associated with url. Empty implies retrieving cookies of all URLs.\n        /// </summary>\n        public string Url { get; set; }\n\n        /// <summary>\n        /// (optional) - Filters cookies by name.\n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// (optional) - Retrieves cookies whose domains match or are subdomains of domains.\n        /// </summary>\n        public string Domain { get; set; }\n\n        /// <summary>\n        /// (optional) - Retrieves cookies whose path matches path.\n        /// </summary>\n        public string Path { get; set; }\n\n        /// <summary>\n        /// (optional) - Filters cookies by their Secure property.\n        /// </summary>\n        public bool? Secure { get; set; }\n\n        /// <summary>\n        /// (optional) - Filters out session or persistent cookies.\n        /// </summary>\n        public bool? Session { get; set; }\n\n        /// <summary>\n        /// (optional) - Filters cookies by httpOnly.\n        /// </summary>\n        public bool? HttpOnly { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/CreateFromBitmapOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class CreateFromBitmapOptions\n    {\n        /// <summary>\n        /// Gets or sets the width in pixels. Required for nativeImage.createFromBitmap(buffer, options).\n        /// </summary>\n        public int? Width { get; set; }\n\n        /// <summary>\n        /// Gets or sets the height in pixels. Required for nativeImage.createFromBitmap(buffer, options).\n        /// </summary>\n        public int? Height { get; set; }\n\n        /// <summary>\n        /// Gets or sets the image scale factor. Optional, defaults to 1.0.\n        /// </summary>\n        public float ScaleFactor { get; set; } = 1.0f;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/CreateFromBufferOptions.cs",
    "content": "namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class CreateFromBufferOptions\n    {\n        /// <summary>\n        /// Gets or sets the width. Required for bitmap buffers passed to nativeImage.createFromBuffer.\n        /// </summary>\n        public int? Width { get; set; }\n\n        /// <summary>\n        /// Gets or sets the height. Required for bitmap buffers passed to nativeImage.createFromBuffer.\n        /// </summary>\n        public int? Height { get; set; }\n\n        /// <summary>\n        /// The image scale factor. Optional, defaults to 1.0.\n        /// </summary>\n        public float ScaleFactor { get; set; } = 1.0f;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/CreateInterruptedDownloadOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class CreateInterruptedDownloadOptions\n    {\n        /// <summary>\n        /// Absolute path of the download.\n        /// </summary>\n        public string Path { get; set; }\n\n        /// <summary>\n        /// Complete URL chain for the download.\n        /// </summary>\n        public string[] UrlChain { get; set; }\n\n        /// <summary>\n        /// (optional) - MIME type of the download.\n        /// </summary>\n        public string MimeType { get; set; }\n\n        /// <summary>\n        /// Start range for the download.\n        /// </summary>\n        public int Offset { get; set; }\n\n        /// <summary>\n        /// Total length of the download.\n        /// </summary>\n        public int Length { get; set; }\n\n        /// <summary>\n        /// Last-Modified header value.\n        /// </summary>\n        public string LastModified { get; set; }\n\n        /// <summary>\n        /// ETag header value.\n        /// </summary>\n        public string ETag { get; set; }\n\n        /// <summary>\n        /// (optional) - Time when download was started in number of seconds since UNIX epoch.\n        /// Electron documents this as a Number (Double).\n        /// </summary>\n        public double? StartTime { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"path\">Absolute path of the download.</param>\n        /// <param name=\"urlChain\">Complete URL chain for the download.</param>\n        /// <param name=\"offset\">Start range for the download.</param>\n        /// <param name=\"length\">Total length of the download.</param>\n        /// <param name=\"lastModified\">Last-Modified header value.</param>\n        /// <param name=\"eTag\">ETag header value.</param>\n        public CreateInterruptedDownloadOptions(string path, string[] urlChain, int offset, int length, string lastModified, string eTag)\n        {\n            Path = path;\n            UrlChain = urlChain;\n            Offset = offset;\n            Length = length;\n            LastModified = lastModified;\n            ETag = eTag;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Data.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public class Data\n    {\n        /// <summary>\n        /// Gets or sets the text.\n        /// </summary>\n        /// <value>\n        /// The text.\n        /// </value>\n        public string Text { get; set; }\n\n        /// <summary>\n        /// Gets or sets the HTML.\n        /// </summary>\n        /// <value>\n        /// The HTML.\n        /// </value>\n        public string Html { get; set; }\n\n        /// <summary>\n        /// Gets or sets the image.\n        /// Maps to clipboard.write({ image: NativeImage }).\n        /// </summary>\n        public NativeImage Image { get; set; }\n\n\n        /// <summary>\n        /// Gets or sets the RTF.\n        /// </summary>\n        /// <value>\n        /// The RTF.\n        /// </value>\n        public string Rtf { get; set; }\n\n        /// <summary>\n        /// The title of the url at text.\n        /// </summary>\n        public string Bookmark { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/DefaultFontFamily.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public class DefaultFontFamily\n    {\n        /// <summary>\n        /// Defaults to Times New Roman.\n        /// </summary>\n        public string Standard { get; set; }\n\n        /// <summary>\n        /// Defaults to Times New Roman.\n        /// </summary>\n        public string Serif { get; set; }\n\n        /// <summary>\n        /// Defaults to Arial.\n        /// </summary>\n        public string SansSerif { get; set; }\n\n        /// <summary>\n        /// Defaults to Courier New.\n        /// </summary>\n        public string Monospace { get; set; }\n\n        /// <summary>\n        /// Defaults to Script.\n        /// </summary>\n        public string Cursive { get; set; }\n\n        /// <summary>\n        /// Defaults to Impact.\n        /// </summary>\n        public string Fantasy { get; set; }\n\n        /// <summary>\n        /// Defaults to Latin Modern Math.\n        /// </summary>\n        public string Math { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/DevToolsMode.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Opens the devtools with specified dock state, can be left, right, bottom, undocked,\n    /// detach. Defaults to last used dock state. In undocked mode it's possible to dock\n    /// back. In detach mode it's not.\n    /// </summary>\n    public enum DevToolsMode\n    {\n        /// <summary>\n        /// The right\n        /// </summary>\n        right,\n\n        /// <summary>\n        /// The bottom\n        /// </summary>\n        bottom,\n\n        /// <summary>\n        /// The undocked\n        /// </summary>\n        undocked,\n\n        /// <summary>\n        /// The detach\n        /// </summary>\n        detach,\n\n        /// <summary>\n        /// The left\n        /// </summary>\n        left,\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Display.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class Display\n    {\n        /// <summary>\n        /// Gets or sets the accelerometer support status; can be 'available', 'unavailable', or 'unknown'.\n        /// </summary>\n        public string AccelerometerSupport { get; set; }\n\n        /// <summary>\n        /// Gets or sets the bounds.\n        /// </summary>\n        /// <value>\n        /// The bounds of the display in DIP points.\n        /// </value>\n        public Rectangle Bounds { get; set; }\n\n        /// <summary>\n        /// Gets or sets the number of bits per pixel.\n        /// </summary>\n        public int ColorDepth { get; set; }\n\n        /// <summary>\n        /// Gets or sets the color space description used for color conversions.\n        /// </summary>\n        public string ColorSpace { get; set; }\n\n        /// <summary>\n        /// Gets or sets the number of bits per color component.\n        /// </summary>\n        public int DepthPerComponent { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the display is detected by the system.\n        /// </summary>\n        public bool Detected { get; set; }\n\n        /// <summary>\n        /// Gets or sets the display refresh rate.\n        /// </summary>\n        public double DisplayFrequency { get; set; }\n\n        /// <summary>\n        /// Gets or sets the unique identifier associated with the display. A value of -1 means the display is invalid or the correct id is not yet known, and a value of -10 means the display is a virtual display assigned to a unified desktop.\n        /// </summary>\n        public long Id { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the display is internal (true) or external (false).\n        /// </summary>\n        public bool Internal { get; set; }\n\n        /// <summary>\n        /// Gets or sets the user-friendly label, determined by the platform.\n        /// </summary>\n        public string Label { get; set; }\n\n        /// <summary>\n        /// Gets or sets the maximum cursor size in native pixels.\n        /// </summary>\n        public Size MaximumCursorSize { get; set; }\n\n        /// <summary>\n        /// Gets or sets the display's origin in pixel coordinates. Only available on windowing systems that position displays in pixel coordinates (e.g., X11).\n        /// </summary>\n        public Point NativeOrigin { get; set; }\n\n        /// <summary>\n        /// Gets or sets the screen rotation in clock-wise degrees. Can be 0, 90, 180, or 270.\n        /// </summary>\n        public int Rotation { get; set; }\n\n        /// <summary>\n        /// Gets or sets the output device's pixel scale factor.\n        /// </summary>\n        public double ScaleFactor { get; set; }\n\n        /// <summary>\n        /// Gets or sets the touch support status; can be 'available', 'unavailable', or 'unknown'.\n        /// </summary>\n        public string TouchSupport { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the display is monochrome.\n        /// </summary>\n        public bool Monochrome { get; set; }\n\n        /// <summary>\n        /// Gets or sets the size.\n        /// </summary>\n        /// <value>\n        /// The size.\n        /// </value>\n        public Size Size { get; set; }\n\n        /// <summary>\n        /// Gets or sets the work area of the display in DIP points.\n        /// </summary>\n        /// <value>\n        /// The work area of the display in DIP points.\n        /// </value>\n        public Rectangle WorkArea { get; set; }\n\n        /// <summary>\n        /// Gets or sets the size of the work area.\n        /// </summary>\n        /// <value>\n        /// The size of the work area.\n        /// </value>\n        public Size WorkAreaSize { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/DisplayBalloonOptions.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public enum DisplayBalloonIconType\n    {\n        none,\n        info,\n        warning,\n        error,\n        custom\n    }\n\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"Windows\")]\n    public class DisplayBalloonOptions\n    {\n        /// <summary>\n        /// Gets or sets the icon.\n        /// </summary>\n        /// <value>\n        /// The icon.\n        /// </value>\n        public string Icon { get; set; }\n\n        /// <summary>\n        /// Gets or sets the title.\n        /// </summary>\n        /// <value>\n        /// The title.\n        /// </value>\n        public string Title { get; set; }\n\n        /// <summary>\n        /// Gets or sets the content.\n        /// </summary>\n        /// <value>\n        /// The content.\n        /// </value>\n        public string Content { get; set; }\n\n        /// <summary>\n        /// (optional) - Icon type for the balloon: none, info, warning, error or custom.\n        /// Default is custom.\n        /// </summary>\n        public DisplayBalloonIconType IconType { get; set; } = DisplayBalloonIconType.custom;\n\n        /// <summary>\n        /// (optional) - Use the large version of the icon. Default is true.\n        /// Maps to Windows NIIF_LARGE_ICON.\n        /// </summary>\n        public bool LargeIcon { get; set; } = true;\n\n        /// <summary>\n        /// (optional) - Do not play the associated sound. Default is false.\n        /// Maps to Windows NIIF_NOSOUND.\n        /// </summary>\n        public bool NoSound { get; set; }\n\n        /// <summary>\n        /// (optional) - Do not display the balloon if the current user is in \"quiet time\".\n        /// Default is false. Maps to Windows NIIF_RESPECT_QUIET_TIME.\n        /// </summary>\n        public bool RespectQuietTime { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/DockBounceType.cs",
    "content": "﻿using System.ComponentModel;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Defines the DockBounceType enumeration.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"macOS\")]\n    public enum DockBounceType\n    {\n        /// <summary>\n        /// Dock icon will bounce until either the application becomes active or the request is canceled.\n        /// </summary>\n        [Description(\"critical\")]\n        Critical,\n\n        /// <summary>\n        /// The dock icon will bounce for one second.\n        /// </summary>\n        [Description(\"informational\")]\n        Informational\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/EnableNetworkEmulationOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class EnableNetworkEmulationOptions\n    {\n        /// <summary>\n        /// Whether to emulate network outage. Defaults to false.\n        /// </summary>\n        public bool Offline { get; set; } = false;\n\n        /// <summary>\n        /// RTT in ms. Defaults to 0 which will disable latency throttling.\n        /// Electron documents this as a Number (Double).\n        /// </summary>\n        public double Latency { get; set; }\n\n        /// <summary>\n        /// Download rate in Bps. Defaults to 0 which will disable download throttling.\n        /// Electron documents this as a Number (Double).\n        /// </summary>\n        public double DownloadThroughput { get; set; }\n\n        /// <summary>\n        /// Upload rate in Bps. Defaults to 0 which will disable upload throttling.\n        /// Electron documents this as a Number (Double).\n        /// </summary>\n        public double UploadThroughput { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Extension.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Docs: https://electronjs.org/docs/api/structures/extension\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class Extension\n    {\n        /// <summary>\n        /// \n        /// </summary>\n        public string Id { get; set; }\n\n        /// <summary>\n        /// Copy of the extension's manifest data.\n        /// </summary>\n        public dynamic Manifest { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// The extension's file path.\n        /// </summary>\n        public string Path { get; set; }\n\n        /// <summary>\n        /// The extension's `chrome-extension://` URL.\n        /// </summary>\n        public string Url { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public string Version { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/FileFilter.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class FileFilter\n    {\n        /// <summary>\n        /// Gets or sets the extensions.\n        /// </summary>\n        /// <value>\n        /// The extensions.\n        /// </value>\n        public string[] Extensions { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name.\n        /// </summary>\n        /// <value>\n        /// The name.\n        /// </value>\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/FileIconOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class FileIconOptions\n    {\n        /// <summary>\n        /// The requested icon size string passed to app.getFileIcon:\n        /// \"small\" (16x16), \"normal\" (32x32), or \"large\" (48x48 on Linux, 32x32 on Windows; unsupported on macOS).\n        /// </summary>\n        public string Size { get; private set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FileIconOptions\"/> class.\n        /// </summary>\n        /// <param name=\"fileIconSize\">Size of the file icon.</param>\n        public FileIconOptions(FileIconSize fileIconSize)\n        {\n            Size = fileIconSize.ToString();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/FileIconSize.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public enum FileIconSize\n    {\n        /// <summary>\n        /// small - 16x16 (per app.getFileIcon size mapping).\n        /// </summary>\n        small,\n\n        /// <summary>\n        /// normal - 32x32 (per app.getFileIcon size mapping).\n        /// </summary>\n        normal,\n\n        /// <summary>\n        /// large - 48x48 on Linux, 32x32 on Windows, unsupported on macOS (per app.getFileIcon size mapping).\n        /// </summary>\n        [SupportedOSPlatform(\"Linux\")]\n        [SupportedOSPlatform(\"Windows\")]\n        large\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/FocusOptions.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Controls the behavior of <see cref=\"App.Focus(FocusOptions)\"/>.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class FocusOptions\n    {\n        /// <summary>\n        /// Make the receiver the active app even if another app is currently active.\n        /// You should seek to use the steal option as sparingly as possible.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        public bool Steal { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/GPUFeatureStatus.cs",
    "content": "using System.Text.Json.Serialization;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Graphics Feature Status from chrome://gpu/ as returned by app.getGPUFeatureStatus().\n    /// Each field reflects the status of a GPU capability reported by Chromium.\n    /// \n    /// Possible values for all fields:\n    /// - disabled_software: Software only. Hardware acceleration disabled (yellow)\n    /// - disabled_off: Disabled (red)\n    /// - disabled_off_ok: Disabled (yellow)\n    /// - unavailable_software: Software only, hardware acceleration unavailable (yellow)\n    /// - unavailable_off: Unavailable (red)\n    /// - unavailable_off_ok: Unavailable (yellow)\n    /// - enabled_readback: Hardware accelerated but at reduced performance (yellow)\n    /// - enabled_force: Hardware accelerated on all pages (green)\n    /// - enabled: Hardware accelerated (green)\n    /// - enabled_on: Enabled (green)\n    /// - enabled_force_on: Force enabled (green)\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class GPUFeatureStatus\n    {\n        /// <summary>\n        /// Gets or sets the status for Canvas.\n        /// </summary>\n        [JsonPropertyName(\"2d_canvas\")]\n        public string Canvas { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for Flash.\n        /// </summary>\n        [JsonPropertyName(\"flash_3d\")]\n        public string Flash3D { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for Flash Stage3D.\n        /// </summary>\n        [JsonPropertyName(\"flash_stage3d\")]\n        public string FlashStage3D { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for Flash Stage3D Baseline profile.\n        /// </summary>\n        [JsonPropertyName(\"flash_stage3d_baseline\")]\n        public string FlashStage3dBaseline { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for Compositing.\n        /// </summary>\n        [JsonPropertyName(\"gpu_compositing\")]\n        public string GpuCompositing { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for Multiple Raster Threads.\n        /// </summary>\n        [JsonPropertyName(\"multiple_raster_threads\")]\n        public string MultipleRasterThreads { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for Native GpuMemoryBuffers.\n        /// </summary>\n        [JsonPropertyName(\"native_gpu_memory_buffers\")]\n        public string NativeGpuMemoryBuffers { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for Rasterization.\n        /// </summary>\n        public string Rasterization { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for Video Decode.\n        /// </summary>\n        [JsonPropertyName(\"video_decode\")]\n        public string VideoDecode { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for Video Encode.\n        /// </summary>\n        [JsonPropertyName(\"video_encode\")]\n        public string VideoEncode { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for VPx Video Decode.\n        /// </summary>\n        [JsonPropertyName(\"vpx_decode\")]\n        public string VpxDecode { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for WebGL.\n        /// </summary>\n        public string Webgl { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status for WebGL2.\n        /// </summary>\n        public string Webgl2 { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/IPostData.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Represents a postData item for loadURL/webContents.loadURL options.\n    /// Valid types per Electron docs: 'rawData' and 'file'.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public interface IPostData\n    {\n        /// <summary>\n        /// One of the following:\n        /// rawData - <see cref=\"UploadRawData\"/>.\n        /// file - <see cref=\"UploadFile\"/>.\n        /// Based on Electron postData definitions.\n        /// </summary>\n        public string Type { get; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ImportCertificateOptions.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Options for app.importCertificate(options) on Linux.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"linux\")]\n    public class ImportCertificateOptions\n    {\n        /// <summary>\n        /// Path for the pkcs12 file.\n        /// </summary>\n        public string Certificate { get; set; }\n\n        /// <summary>\n        /// Passphrase for the certificate.\n        /// </summary>\n        public string Password { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/InputEvent.cs",
    "content": "using System.Collections.Generic;\n\nnamespace ElectronNET.API.Entities\n{\n    using ElectronNET.Converter;\n    using System.Text.Json.Serialization;\n\n    /// <summary>\n    /// Input event payload as used by webContents 'input-event' and 'before-input-event'.\n    /// Fields map to KeyboardEvent properties where noted, and type/modifiers follow Electron's InputEvent structure.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class InputEvent\n    {\n        /// <summary>\n        /// Equivalent to KeyboardEvent.key.\n        /// </summary>\n        public string Key { get; set; } = \"\";\n\n        /// <summary>\n        /// Equivalent to KeyboardEvent.code.\n        /// </summary>\n        public string Code { get; set; } = \"\";\n\n        /// <summary>\n        /// Equivalent to KeyboardEvent.repeat.\n        /// </summary>\n        public bool IsAutoRepeat { get; set; } = false;\n\n        /// <summary>\n        /// Equivalent to KeyboardEvent.isComposing.\n        /// </summary>\n        public bool IsComposing { get; set; } = false;\n\n        /// <summary>\n        /// Equivalent to KeyboardEvent.shiftKey.\n        /// </summary>\n        public bool Shift { get; set; } = false;\n\n        /// <summary>\n        /// Equivalent to KeyboardEvent.controlKey.\n        /// </summary>\n        public bool Control { get; set; } = false;\n\n        /// <summary>\n        /// Equivalent to KeyboardEvent.altKey.\n        /// </summary>\n        public bool Alt { get; set; } = false;\n\n        /// <summary>\n        /// Equivalent to KeyboardEvent.metaKey.\n        /// </summary>\n        public bool Meta { get; set; } = false;\n\n        /// <summary>\n        /// Equivalent to KeyboardEvent.location.\n        /// </summary>\n        public int Location { get; set; } = 0;\n\n        /// <summary>\n        /// An array of modifiers of the event, can be `shift`, `control`, `ctrl`, `alt`,\n        /// `meta`, `command`, `cmd`, `iskeypad`, `isautorepeat`, `leftbuttondown`,\n        /// `middlebuttondown`, `rightbuttondown`, `capslock`, `numlock`, `left`, `right`.\n        /// </summary>\n        [JsonConverter(typeof(ModifierTypeListConverter))]\n        public List<ModifierType> Modifiers { get; set; }\n\n        /// <summary>\n        /// For MouseInputEvent: The x-coordinate of the event (Integer).\n        /// </summary>\n        public int? X { get; set; }\n\n        /// <summary>\n        /// For MouseInputEvent: The y-coordinate of the event (Integer).\n        /// </summary>\n        public int? Y { get; set; }\n\n        /// <summary>\n        /// For MouseInputEvent: The button pressed, can be 'left', 'middle', or 'right' (optional).\n        /// </summary>\n        public string Button { get; set; }\n\n        /// <summary>\n        /// For MouseInputEvent: Global x in screen coordinates (Integer, optional).\n        /// </summary>\n        public int? GlobalX { get; set; }\n\n        /// <summary>\n        /// For MouseInputEvent: Global y in screen coordinates (Integer, optional).\n        /// </summary>\n        public int? GlobalY { get; set; }\n\n        /// <summary>\n        /// For MouseInputEvent: Movement delta on x-axis since last event (Integer, optional).\n        /// </summary>\n        public int? MovementX { get; set; }\n\n        /// <summary>\n        /// For MouseInputEvent: Movement delta on y-axis since last event (Integer, optional).\n        /// </summary>\n        public int? MovementY { get; set; }\n\n        /// <summary>\n        /// For MouseInputEvent: Click count (Integer, optional).\n        /// </summary>\n        public int? ClickCount { get; set; }\n\n        /// <summary>\n        /// For MouseWheelInputEvent: Horizontal scroll delta (Integer, optional).\n        /// </summary>\n        public int? DeltaX { get; set; }\n\n        /// <summary>\n        /// For MouseWheelInputEvent: Vertical scroll delta (Integer, optional).\n        /// </summary>\n        public int? DeltaY { get; set; }\n\n        /// <summary>\n        /// For MouseWheelInputEvent: Horizontal wheel ticks (Integer, optional).\n        /// </summary>\n        public int? WheelTicksX { get; set; }\n\n        /// <summary>\n        /// For MouseWheelInputEvent: Vertical wheel ticks (Integer, optional).\n        /// </summary>\n        public int? WheelTicksY { get; set; }\n\n        /// <summary>\n        /// For MouseWheelInputEvent: Horizontal acceleration ratio (Integer, optional).\n        /// </summary>\n        public int? AccelerationRatioX { get; set; }\n\n        /// <summary>\n        /// For MouseWheelInputEvent: Vertical acceleration ratio (Integer, optional).\n        /// </summary>\n        public int? AccelerationRatioY { get; set; }\n\n        /// <summary>\n        /// For MouseWheelInputEvent: True if wheel deltas are precise (optional).\n        /// </summary>\n        public bool? HasPreciseScrollingDeltas { get; set; }\n\n        /// <summary>\n        /// For MouseWheelInputEvent: True if the target can scroll (optional).\n        /// </summary>\n        public bool? CanScroll { get; set; }\n\n        /// <summary>\n        /// Can be `undefined`, `mouseDown`, `mouseUp`, `mouseMove`, `mouseEnter`,\n        /// `mouseLeave`, `contextMenu`, `mouseWheel`, `rawKeyDown`, `keyDown`, `keyUp`, `char`,\n        /// `gestureScrollBegin`, `gestureScrollEnd`, `gestureScrollUpdate`,\n        /// `gestureFlingStart`, `gestureFlingCancel`, `gesturePinchBegin`,\n        /// `gesturePinchEnd`, `gesturePinchUpdate`, `gestureTapDown`, `gestureShowPress`,\n        /// `gestureTap`, `gestureTapCancel`, `gestureShortPress`, `gestureLongPress`,\n        /// `gestureLongTap`, `gestureTwoFingerTap`, `gestureTapUnconfirmed`,\n        /// `gestureDoubleTap`, `touchStart`, `touchMove`, `touchEnd`, `touchCancel`,\n        /// `touchScrollStarted`, `pointerDown`, `pointerUp`, `pointerMove`,\n        /// `pointerRawUpdate`, `pointerCancel` or `pointerCausedUaAction`.\n        /// </summary>\n        public InputEventType Type { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/InputEventType.cs",
    "content": "﻿namespace ElectronNET.API.Entities;\n\n/// <summary>\n/// \n/// </summary>\npublic enum InputEventType\n{\n    /// <summary>\n    /// \n    /// </summary>\n    undefined,\n\n    /// <summary>\n    /// \n    /// </summary>\n    mouseDown,\n\n    /// <summary>\n    /// \n    /// </summary>\n    mouseUp,\n\n    /// <summary>\n    /// \n    /// </summary>\n    mouseMove,\n\n    /// <summary>\n    /// \n    /// </summary>\n    mouseEnter,\n\n    /// <summary>\n    /// \n    /// </summary>\n    mouseLeave,\n\n    /// <summary>\n    /// \n    /// </summary>\n    contextMenu,\n\n    /// <summary>\n    /// \n    /// </summary>\n    mouseWheel,\n\n    /// <summary>\n    /// \n    /// </summary>\n    rawKeyDown,\n\n    /// <summary>\n    /// \n    /// </summary>\n    keyDown,\n\n    /// <summary>\n    /// \n    /// </summary>\n    keyUp,\n\n    /// <summary>\n    /// \n    /// </summary>\n    @char,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureScrollBegin,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureScrollEnd,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureScrollUpdate,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureFlingStart,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureFlingCancel,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gesturePinchBegin,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gesturePinchEnd,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gesturePinchUpdate,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureTapDown,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureShowPress,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureTap,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureTapCancel,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureShortPress,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureLongPress,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureLongTap,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureTwoFingerTap,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureTapUnconfirmed,\n\n    /// <summary>\n    /// \n    /// </summary>\n    gestureDoubleTap,\n\n    /// <summary>\n    /// \n    /// </summary>\n    touchStart,\n\n    /// <summary>\n    /// \n    /// </summary>\n    touchMove,\n\n    /// <summary>\n    /// \n    /// </summary>\n    touchEnd,\n\n    /// <summary>\n    /// \n    /// </summary>\n    touchCancel,\n\n    /// <summary>\n    /// \n    /// </summary>\n    touchScrollStarted,\n\n    /// <summary>\n    /// \n    /// </summary>\n    pointerDown,\n\n    /// <summary>\n    /// \n    /// </summary>\n    pointerUp,\n\n    /// <summary>\n    /// \n    /// </summary>\n    pointerMove,\n\n    /// <summary>\n    /// \n    /// </summary>\n    pointerRawUpdate,\n\n    /// <summary>\n    /// \n    /// </summary>\n    pointerCancel,\n\n    /// <summary>\n    /// \n    /// </summary>\n    pointerCausedUaAction\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/JumpListCategory.cs",
    "content": "using System.Text.Json.Serialization;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Jump List category definition used with app.setJumpList(categories).\n    /// Matches Electron's JumpListCategory structure.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"windows\")]\n    public class JumpListCategory\n    {\n        /// <summary>\n        /// Gets or sets the name; must be set if <c>type</c> is <c>custom</c>, otherwise it should be omitted.\n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Gets or sets the array of <see cref=\"JumpListItem\"/> objects if <c>type</c> is <c>tasks</c> or <c>custom</c>; otherwise it should be omitted.\n        /// </summary>\n        public JumpListItem[] Items { get; set; }\n\n        /// <summary>\n        /// Gets or sets the category type. One of: <c>tasks</c> | <c>frequent</c> | <c>recent</c> | <c>custom</c>.\n        /// </summary>\n        public JumpListCategoryType Type { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/JumpListCategoryType.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Jump list category kinds for app.setJumpList (Windows).\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"Windows\")]\n    public enum JumpListCategoryType\n    {\n        /// <summary>\n        /// The tasks\n        /// </summary>\n        tasks,\n\n        /// <summary>\n        /// The frequent\n        /// </summary>\n        frequent,\n\n        /// <summary>\n        /// The recent\n        /// </summary>\n        recent,\n\n        /// <summary>\n        /// The custom\n        /// </summary>\n        custom\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/JumpListItem.cs",
    "content": "using System.Text.Json.Serialization;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Jump List item used in app.setJumpList(categories) on Windows.\n    /// Matches Electron's JumpListItem structure.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"windows\")]\n    public class JumpListItem\n    {\n        /// <summary>\n        /// Gets or sets the command line arguments when <c>program</c> is executed. Should only be set if <c>type</c> is <c>task</c>.\n        /// </summary>\n        public string Args { get; set; }\n\n        /// <summary>\n        /// Gets or sets the description of the task (displayed in a tooltip). Should only be set if <c>type</c> is <c>task</c>. Maximum length 260 characters.\n        /// </summary>\n        public string Description { get; set; }\n\n        /// <summary>\n        /// Gets or sets the index of the icon in the resource file. If a resource file contains multiple\n        /// icons this value can be used to specify the zero-based index of the icon that\n        /// should be displayed for this task. If a resource file contains only one icon,\n        /// this property should be set to zero.\n        /// </summary>\n        public int IconIndex { get; set; }\n\n        /// <summary>\n        /// Gets or sets the absolute path to an icon to be displayed in a Jump List, which can be an\n        /// arbitrary resource file that contains an icon(e.g. .ico, .exe, .dll). You can\n        /// usually specify process.execPath to show the program icon.\n        /// </summary>\n        public string IconPath { get; set; }\n\n        /// <summary>\n        /// Gets or sets the path of the file to open; should only be set if <c>type</c> is <c>file</c>.\n        /// </summary>\n        public string Path { get; set; }\n\n        /// <summary>\n        /// Gets or sets the path of the program to execute, usually specify process.execPath\n        /// which opens the current program. Should only be set if <c>type</c> is <c>task</c>.\n        /// </summary>\n        public string Program { get; set; }\n\n        /// <summary>\n        /// Gets or sets the text to be displayed for the item in the Jump List. Should only be set if <c>type</c> is <c>task</c>.\n        /// </summary>\n        public string Title { get; set; }\n\n        /// <summary>\n        /// Gets or sets the item type. One of: <c>task</c> | <c>separator</c> | <c>file</c>.\n        /// </summary>\n        public JumpListItemType Type { get; set; }\n\n        /// <summary>\n        /// Gets or sets the working directory. Default is empty.\n        /// </summary>\n        public string WorkingDirectory { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/JumpListItemType.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Jump list item kinds for app.setJumpList (Windows).\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"Windows\")]\n    public enum JumpListItemType\n    {\n        /// <summary>\n        /// The task\n        /// </summary>\n        task,\n\n        /// <summary>\n        /// The separator\n        /// </summary>\n        separator,\n\n        /// <summary>\n        /// The file\n        /// </summary>\n        file\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/JumpListSettings.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Settings returned by app.getJumpListSettings() on Windows.\n    /// Matches Electron's JumpListSettings object.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"windows\")]\n    public class JumpListSettings\n    {\n        /// <summary>\n        /// The minimum number of items that will be shown in the Jump List.\n        /// </summary>\n        public int MinItems { get; set; } = 0;\n\n        /// <summary>\n        /// Array of JumpListItem objects that correspond to items that the user has explicitly removed from custom categories\n        /// in the Jump List. These items must not be re-added to the Jump List in the next call to app.setJumpList(categories);\n        /// Windows will not display any custom category that contains any of the removed items.\n        /// </summary>\n        public JumpListItem[] RemovedItems { get; set; } = new JumpListItem[0];\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/LoadURLOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Options for BrowserWindow.loadURL(url, options) / webContents.loadURL(url, options).\n    /// Matches Electron's loadURL options.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class LoadURLOptions\n    {\n        /// <summary>\n        /// An HTTP Referrer URL. In Electron this may be a string or a Referrer object.\n        /// </summary>\n        public string HttpReferrer { get; set; }\n\n        /// <summary>\n        /// A user agent originating the request.\n        /// </summary>\n        public string UserAgent { get; set; }\n\n        /// <summary>\n        /// Base URL (with trailing path separator) for files to be loaded by the data URL.\n        /// Needed only if the specified URL is a data URL and needs to load other files.\n        /// </summary>\n        public string BaseURLForDataURL { get; set; }\n\n        /// <summary>\n        /// Extra headers separated by \"\\n\".\n        /// </summary>\n        public string ExtraHeaders { get; set; }\n\n        /// <summary>\n        /// Post data for the request. Matches Electron's postData: (UploadRawData | UploadFile)[]\n        /// </summary>\n        public IPostData[] PostData { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/LoginItemLaunchItem.cs",
    "content": "using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Windows launch entry as returned by app.getLoginItemSettings().launchItems.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"windows\")]\n    public class LoginItemLaunchItem\n    {\n        /// <summary>\n        /// Name value of a registry entry.\n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// The executable to an app that corresponds to a registry entry.\n        /// </summary>\n        public string Path { get; set; }\n\n        /// <summary>\n        /// The command-line arguments to pass to the executable.\n        /// </summary>\n        public string[] Args { get; set; }\n\n        /// <summary>\n        /// One of <c>user</c> or <c>machine</c>. Indicates whether the registry entry is under HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE.\n        /// </summary>\n        public string Scope { get; set; }\n\n        /// <summary>\n        /// True if the app registry key is startup approved and therefore shows as enabled in Task Manager and Windows settings.\n        /// </summary>\n        public bool Enabled { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/LoginItemSettings.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Return object for app.getLoginItemSettings() on macOS and Windows.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class LoginItemSettings\n    {\n        /// <summary>\n        /// <see langword=\"true\"/> if the app is set to open at login.\n        /// </summary>\n        public bool OpenAtLogin { get; set; }\n\n        /// <summary>\n        /// <see langword=\"true\"/> if the app is set to open as hidden at login. Deprecated on macOS 13 and up; not available\n        /// on <see href=\"https://www.electronjs.org/docs/tutorial/mac-app-store-submission-guide\">MAS builds</see>.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool OpenAsHidden { get; set; }\n\n        /// <summary>\n        /// <see langword=\"true\"/> if the app was opened at login automatically. This setting is not available\n        /// on <see href=\"https://www.electronjs.org/docs/tutorial/mac-app-store-submission-guide\">MAS builds</see>.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool WasOpenedAtLogin { get; set; }\n\n        /// <summary>\n        /// <see langword=\"true\"/> if the app was opened as a hidden login item. This indicates that the app should not\n        /// open any windows at startup. Deprecated on macOS 13 and up; not available on\n        /// <see href=\"https://www.electronjs.org/docs/tutorial/mac-app-store-submission-guide\">MAS builds</see>.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool WasOpenedAsHidden { get; set; }\n\n        /// <summary>\n        /// <see langword=\"true\"/> if the app was opened as a login item that should restore the state from the previous\n        /// session. This indicates that the app should restore the windows that were open the last time the app was closed.\n        /// Deprecated on macOS 13 and up; not available on <see href=\"https://www.electronjs.org/docs/tutorial/mac-app-store-submission-guide\">MAS builds</see>.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool RestoreState { get; set; }\n\n        /// <summary>\n        /// macOS status: one of <c>not-registered</c>, <c>enabled</c>, <c>requires-approval</c>, or <c>not-found</c>.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string Status { get; set; }\n\n        /// <summary>\n        /// Windows: true if app is set to open at login and its run key is not deactivated.\n        /// Differs from <c>OpenAtLogin</c> as it ignores the <c>args</c> option; this is true if the given executable would be launched at login with any arguments.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public bool ExecutableWillLaunchAtLogin { get; set; }\n\n        /// <summary>\n        /// Windows launch entries found in registry.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public LoginItemLaunchItem[] LaunchItems { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/LoginItemSettingsOptions.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public class LoginItemSettingsOptions\n    {\n        /// <summary>\n        /// The executable path to compare against. Defaults to process.execPath.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string Path { get; set; }\n\n        /// <summary>\n        /// The command-line arguments to compare against. Defaults to an empty array.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string[] Args { get; set; }\n\n        /// <summary>\n        /// The type of service to query on macOS 13+. Defaults to 'mainAppService'. Only available on macOS 13 and up.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string Type { get; set; }\n\n        /// <summary>\n        /// The name of the service. Required if type is non-default. Only available on macOS 13 and up.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string ServiceName { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/LoginSettings.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Settings object for app.setLoginItemSettings() on macOS and Windows.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class LoginSettings\n    {\n        /// <summary>\n        /// <see langword=\"true\"/> to open the app at login, <see langword=\"false\"/> to remove the app as a login item.\n        /// Defaults to <see langword=\"false\"/>.\n        /// </summary>\n        public bool OpenAtLogin { get; set; }\n\n        /// <summary>\n        /// <see langword=\"true\"/> to open the app as hidden. Defaults to <see langword=\"false\"/>. The user can edit this\n        /// setting from the System Preferences so app.getLoginItemSettings().wasOpenedAsHidden should be checked when the app is\n        /// opened to know the current value. This setting is not available on <see href=\"https://www.electronjs.org/docs/tutorial/mac-app-store-submission-guide\">MAS builds</see> and does not work on macOS 13 and up.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool OpenAsHidden { get; set; }\n\n        /// <summary>\n        /// The executable to launch at login. Defaults to process.execPath.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string Path { get; set; }\n\n        /// <summary>\n        /// The command-line arguments to pass to the executable. Defaults to an empty\n        /// array.Take care to wrap paths in quotes.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string[] Args { get; set; }\n\n        /// <summary>\n        /// The type of service to add as a login item. Defaults to 'mainAppService'. Only available on macOS 13 and up.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string Type { get; set; }\n\n        /// <summary>\n        /// The name of the service. Required if <c>Type</c> is non-default. Only available on macOS 13 and up.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string ServiceName { get; set; }\n\n        /// <summary>\n        /// Change the startup approved registry key and enable/disable the app in Task Manager and Windows Settings. Defaults to true.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public bool Enabled { get; set; } = true;\n\n        /// <summary>\n        /// Value name to write into registry. Defaults to the app's AppUserModelId().\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Margins.cs",
    "content": "﻿namespace ElectronNET.API.Entities;\n\n/// <summary>\n/// Margins object used by webContents.print options and webContents.printToPDF.\n/// </summary>\n/// <remarks>Up-to-date with Electron API 39.2</remarks>\npublic class Margins\n{\n    /// <summary>\n    /// Gets or sets the margin type. Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen,\n    /// you will also need to specify `top`, `bottom`, `left`, and `right`.\n    /// </summary>\n    public string MarginType { get; set; }\n\n    /// <summary>\n    /// Gets or sets the top margin of the printed web page. Units depend on API:\n    /// - webContents.print: pixels\n    /// - webContents.printToPDF: inches\n    /// </summary>\n    public double Top { get; set; }\n\n    /// <summary>\n    /// Gets or sets the bottom margin of the printed web page. Units depend on API:\n    /// - webContents.print: pixels\n    /// - webContents.printToPDF: inches\n    /// </summary>\n    public double Bottom { get; set; }\n\n    /// <summary>\n    /// Gets or sets the left margin of the printed web page. Units depend on API:\n    /// - webContents.print: pixels\n    /// - webContents.printToPDF: inches\n    /// </summary>\n    public double Left { get; set; }\n\n    /// <summary>\n    /// Gets or sets the right margin of the printed web page. Units depend on API:\n    /// - webContents.print: pixels\n    /// - webContents.printToPDF: inches\n    /// </summary>\n    public double Right { get; set; }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/MemoryInfo.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Process memory info as returned by process.getProcessMemoryInfo().\n    /// Values are reported in Kilobytes.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class MemoryInfo\n    {\n        /// <summary>\n        /// Gets or sets the amount of memory currently pinned to actual physical RAM.\n        /// </summary>\n        public int WorkingSetSize { get; set; }\n\n        /// <summary>\n        /// Gets or sets the maximum amount of memory that has ever been pinned to actual physical RAM.\n        /// </summary>\n        public int PeakWorkingSetSize { get; set; }\n\n        /// <summary>\n        /// Gets or sets the amount of memory not shared by other processes, such as JS heap or HTML content. Windows only.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public int PrivateBytes { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/MenuItem.cs",
    "content": "using System;\nusing System.Text.Json.Serialization;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class MenuItem\n    {\n        /// <summary>\n        /// Will be called with click(menuItem, browserWindow, event) when the menu item is\n        /// clicked.\n        /// </summary>\n        [JsonIgnore]\n        public Action Click { get; set; }\n\n        /// <summary>\n        /// Gets or sets the action (role) of the menu item. When specified, the click property will be ignored.\n        /// </summary>\n        public MenuRole Role { get; set; }\n\n        /// <summary>\n        /// Gets or sets the menu item type. Can be normal, separator, submenu, checkbox, radio, header (macOS 14+), or palette (macOS 14+).\n        /// </summary>\n        public MenuType Type { get; set; }\n\n\n        /// <summary>\n        /// Gets or sets the label.\n        /// </summary>\n        /// <value>\n        /// The label.\n        /// </value>\n        public string Label { get; set; }\n\n\n        /// <summary>\n        /// Gets or sets the sublabel.\n        /// </summary>\n        /// <value>\n        /// The sublabel.\n        /// </value>\n        [SupportedOSPlatform(\"macos\")]\n        public string Sublabel { get; set; }\n\n        /// <summary>\n        /// Hover text for this menu item (macOS).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string ToolTip { get; set; }\n\n\n        /// <summary>\n        /// Gets or sets the accelerator.\n        /// </summary>\n        /// <value>\n        /// The accelerator.\n        /// </value>\n        public string Accelerator { get; set; }\n\n\n        /// <summary>\n        /// Gets or sets the icon.\n        /// </summary>\n        /// <value>\n        /// The icon.\n        /// </value>\n        public string Icon { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the item is enabled. If false, the menu item will be greyed out and unclickable.\n        /// </summary>\n        public bool Enabled { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the item is visible. If false, the menu item will be entirely hidden.\n        /// </summary>\n        public bool Visible { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the accelerator should work when the item is hidden. Default is true (macOS).\n        /// When false, prevents the accelerator from triggering the item if the item is not visible.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool? AcceleratorWorksWhenHidden { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the accelerator should be registered with the system or only displayed (Linux/Windows). Defaults to true.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        [SupportedOSPlatform(\"linux\")]\n        public bool? RegisterAccelerator { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the item is checked. Should only be specified for checkbox or radio items.\n        /// </summary>\n        public bool Checked { get; set; }\n\n        /// <summary>\n        /// Should be specified for submenu type menu items. If submenu is specified, the\n        /// type: 'submenu' can be omitted.If the value is not a Menu then it will be\n        /// automatically converted to one using Menu.buildFromTemplate.\n        /// </summary>\n        public MenuItem[] Submenu { get; set; }\n\n        /// <summary>\n        /// The item to share when the role is shareMenu (macOS).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public SharingItem SharingItem { get; set; }\n\n        /// <summary>\n        /// Gets or sets a unique id within a single menu. If defined then it can be used as a reference for placement.\n        /// </summary>\n        public string Id { get; internal set; }\n\n        /// <summary>\n        /// This field allows fine-grained definition of the specific location within a given menu.\n        /// </summary>\n        public string Position { get; set; }\n\n        /// <summary>\n        /// Gets or sets a list of item ids. Inserts this item before the item(s) with the specified id(s).\n        /// If the referenced item doesn't exist the item will be inserted at the end of the menu.\n        /// Also implies that this item should be placed in the same group as the referenced item(s).\n        /// </summary>\n        public string[] Before { get; set; }\n\n        /// <summary>\n        /// Gets or sets a list of item ids. Inserts this item after the item(s) with the specified id(s).\n        /// If the referenced item doesn't exist the item will be inserted at the end of the menu.\n        /// </summary>\n        public string[] After { get; set; }\n\n        /// <summary>\n        /// Gets or sets a list of item ids. Places this item's containing group before the containing group\n        /// of the item(s) with the specified id(s).\n        /// </summary>\n        public string[] BeforeGroupContaining { get; set; }\n\n        /// <summary>\n        /// Gets or sets a list of item ids. Places this item's containing group after the containing group\n        /// of the item(s) with the specified id(s).\n        /// </summary>\n        public string[] AfterGroupContaining { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/MenuRole.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public enum MenuRole\n    {\n        /// <summary>\n        /// The undo\n        /// </summary>\n        undo = 1,\n\n        /// <summary>\n        /// The redo\n        /// </summary>\n        redo,\n\n        /// <summary>\n        /// The cut\n        /// </summary>\n        cut,\n\n        /// <summary>\n        /// The copy\n        /// </summary>\n        copy,\n\n        /// <summary>\n        /// The paste\n        /// </summary>\n        paste,\n\n        /// <summary>\n        /// The pasteAndMatchStyle\n        /// </summary>\n        pasteAndMatchStyle,\n\n        /// <summary>\n        /// The selectAll\n        /// </summary>\n        selectAll,\n\n        /// <summary>\n        /// The delete\n        /// </summary>\n        delete,\n\n        /// <summary>\n        /// Minimize current window\n        /// </summary>\n        minimize,\n\n        /// <summary>\n        /// Close current window\n        /// </summary>\n        close,\n\n        /// <summary>\n        /// Quit the application\n        /// </summary>\n        quit,\n\n        /// <summary>\n        /// Reload the current window\n        /// </summary>\n        reload,\n\n        /// <summary>\n        /// Reload the current window ignoring the cache.\n        /// </summary>\n        forceReload,\n\n        /// <summary>\n        /// Toggle developer tools in the current window\n        /// </summary>\n        toggleDevTools,\n\n        /// <summary>\n        /// Toggle full screen mode on the current window\n        /// </summary>\n        togglefullscreen,\n\n        /// <summary>\n        /// Reset the focused page’s zoom level to the original size\n        /// </summary>\n        resetZoom,\n\n        /// <summary>\n        /// Zoom in the focused page by 10%\n        /// </summary>\n        zoomIn,\n\n        /// <summary>\n        /// Zoom out the focused page by 10%\n        /// </summary>\n        zoomOut,\n\n        /// <summary>\n        /// Whole default “Edit” menu (Undo, Copy, etc.)\n        /// </summary>\n        editMenu,\n\n        /// <summary>\n        /// Whole default “Window” menu (Minimize, Close, etc.)\n        /// </summary>\n        windowMenu,\n\n        /// <summary>\n        /// Only macOS: Map to the orderFrontStandardAboutPanel action\n        /// </summary>\n        about,\n\n        /// <summary>\n        /// Only macOS: Map to the hide action\n        /// </summary>\n        hide,\n\n        /// <summary>\n        /// Only macOS: Map to the hideOtherApplications action\n        /// </summary>\n        hideOthers,\n\n        /// <summary>\n        /// Only macOS: Map to the unhideAllApplications action\n        /// </summary>\n        unhide,\n\n        /// <summary>\n        /// Only macOS: Map to the startSpeaking action\n        /// </summary>\n        startSpeaking,\n\n        /// <summary>\n        /// Only macOS: Map to the stopSpeaking action\n        /// </summary>\n        stopSpeaking,\n\n        /// <summary>\n        /// Only macOS: Map to the arrangeInFront action\n        /// </summary>\n        front,\n\n        /// <summary>\n        /// Only macOS: Map to the performZoom action\n        /// </summary>\n        zoom,\n\n        /// <summary>\n        /// Only macOS: The submenu is a “Window” menu\n        /// </summary>\n        window,\n\n        /// <summary>\n        /// Only macOS: The submenu is a “Help” menu\n        /// </summary>\n        help,\n\n        /// <summary>\n        /// Only macOS: The submenu is a “Services” menu\n        /// </summary>\n        services,\n\n        /// <summary>\n        /// Toggle built-in spellchecker.\n        /// </summary>\n        toggleSpellChecker,\n\n        /// <summary>\n        /// The submenu is a \"File\" menu.\n        /// </summary>\n        fileMenu,\n\n        /// <summary>\n        /// The submenu is a \"View\" menu.\n        /// </summary>\n        viewMenu,\n\n        /// <summary>\n        /// The application menu.\n        /// </summary>\n        appMenu,\n\n        /// <summary>\n        /// The submenu is a \"Share\" menu.\n        /// </summary>\n        shareMenu,\n\n        /// <summary>\n        /// Displays a list of files recently opened by the app.\n        /// </summary>\n        recentDocuments,\n\n        /// <summary>\n        /// Clear the recent documents list.\n        /// </summary>\n        clearRecentDocuments,\n\n        /// <summary>\n        /// Toggle the tab bar (macOS).\n        /// </summary>\n        toggleTabBar,\n\n        /// <summary>\n        /// Select the next tab (macOS).\n        /// </summary>\n        selectNextTab,\n\n        /// <summary>\n        /// Select the previous tab (macOS).\n        /// </summary>\n        selectPreviousTab,\n\n        /// <summary>\n        /// Show all tabs (macOS).\n        /// </summary>\n        showAllTabs,\n\n        /// <summary>\n        /// Merge all windows (macOS).\n        /// </summary>\n        mergeAllWindows,\n\n        /// <summary>\n        /// Move the current tab to a new window (macOS).\n        /// </summary>\n        moveTabToNewWindow,\n\n        /// <summary>\n        /// Show substitutions panel (macOS).\n        /// </summary>\n        showSubstitutions,\n\n        /// <summary>\n        /// Toggle smart quotes (macOS).\n        /// </summary>\n        toggleSmartQuotes,\n\n        /// <summary>\n        /// Toggle smart dashes (macOS).\n        /// </summary>\n        toggleSmartDashes,\n\n        /// <summary>\n        /// Toggle text replacement (macOS).\n        /// </summary>\n        toggleTextReplacement,\n\n        // Backwards-compatibility aliases (old identifiers) to avoid breaking existing code.\n        // These map to the same enum values as their official values.\n        pasteandmatchstyle = pasteAndMatchStyle,\n        selectall = selectAll,\n        forcereload = forceReload,\n        toggledevtools = toggleDevTools,\n        resetzoom = resetZoom,\n        zoomin = zoomIn,\n        zoomout = zoomOut,\n        hideothers = hideOthers,\n        startspeaking = startSpeaking,\n        stopspeaking = stopSpeaking,\n        togglespellchecker = toggleSpellChecker,\n        togglesmartquotes = toggleSmartQuotes,\n        togglesmartdashes = toggleSmartDashes,\n        toggletextreplacement = toggleTextReplacement\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/MenuType.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Menu item types matching Electron's MenuItem.type values.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public enum MenuType\n    {\n        /// <summary>\n        /// Normal menu item.\n        /// </summary>\n        normal,\n\n        /// <summary>\n        /// Separator between items.\n        /// </summary>\n        separator,\n\n        /// <summary>\n        /// Submenu container.\n        /// </summary>\n        submenu,\n\n        /// <summary>\n        /// Checkbox item.\n        /// </summary>\n        checkbox,\n\n        /// <summary>\n        /// Radio item.\n        /// </summary>\n        radio,\n\n        /// <summary>\n        /// Header item (macOS 14+).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        header,\n\n        /// <summary>\n        /// Palette item (macOS 14+).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        palette\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/MessageBoxOptions.cs",
    "content": "using System.Text.Json.Serialization;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Options for dialog.showMessageBox / dialog.showMessageBoxSync.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class MessageBoxOptions\n    {\n        /// <summary>\n        /// Gets or sets the type. Can be \"none\", \"info\", \"error\", \"question\" or \"warning\". On Windows, \"question\" displays the same icon as \"info\", unless you set an icon using the \"icon\" option. On macOS, both \"warning\" and \"error\" display the same warning icon.\n        /// </summary>\n        public MessageBoxType Type { get; set; }\n\n        /// <summary>\n        /// Gets or sets the array of texts for buttons. On Windows, an empty array will result in one button labeled \"OK\".\n        /// </summary>\n        public string[] Buttons { get; set; }\n\n        /// <summary>\n        /// Gets or sets the index of the button in the buttons array which will be selected by default when the message box opens.\n        /// </summary>\n        public int DefaultId { get; set; }\n\n        /// <summary>\n        /// Gets or sets the title of the message box; some platforms will not show it.\n        /// </summary>\n        public string Title { get; set; }\n\n        /// <summary>\n        /// Gets or sets the content of the message box.\n        /// </summary>\n        public string Message { get; set; }\n\n        /// <summary>\n        /// Gets or sets the extra information of the message.\n        /// </summary>\n        public string Detail { get; set; }\n\n        /// <summary>\n        /// Gets or sets the checkbox label. If provided, the message box will include a checkbox with the given label.\n        /// </summary>\n        public string CheckboxLabel { get; set; }\n\n        /// <summary>\n        /// Gets or sets the initial checked state of the checkbox. Defaults to false.\n        /// </summary>\n        public bool CheckboxChecked { get; set; }\n\n        /// <summary>\n        /// Gets or sets the icon for the message box.\n        /// </summary>\n        public string Icon { get; set; }\n\n        /// <summary>\n        /// Gets or sets the custom width of the text in the message box.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public int? TextWidth { get; set; }\n\n        /// <summary>\n        /// Gets or sets the index of the button to be used to cancel the dialog via the Esc key. By default this is assigned to the first button with \"cancel\" or \"no\" as the label. If no such labeled buttons exist and this option is not set, 0 will be used.\n        /// </summary>\n        public int CancelId { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to disable Windows command-links behavior (noLink).\n        /// On Windows Electron will try to figure out which one of the buttons are common buttons (like \"Cancel\" or \"Yes\"), and show the others as command links in the dialog. Set to true to disable this behavior.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public bool NoLink { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to normalize the keyboard access keys across platforms. Default is false. Enabling this assumes '&amp;' is used in the button labels for the placement of the keyboard\n        /// shortcut access key and labels will be converted so they work correctly on each\n        /// platform, '&amp;' characters are removed on macOS, converted to '_' on Linux, and left\n        /// untouched on Windows. For example, a button label of \"View\" will be converted to \"Vie_w\" on Linux and \"View\" on macOS and can be selected via Alt-W on Windows and\n        /// Linux.\n        /// </summary>\n        public bool NormalizeAccessKeys { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MessageBoxOptions\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public MessageBoxOptions(string message)\n        {\n            Message = message;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/MessageBoxResult.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Result returned by dialog.showMessageBox / dialog.showMessageBoxSync.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class MessageBoxResult\n    {\n        /// <summary>\n        /// The index of the clicked button.\n        /// </summary>\n        public int Response { get; set; }\n\n        /// <summary>\n        /// The checked state of the checkbox if CheckboxLabel was set; otherwise false.\n        /// </summary>\n        public bool CheckboxChecked { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/MessageBoxType.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Message box type for dialog.showMessageBox/showMessageBoxSync.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public enum MessageBoxType\n    {\n        /// <summary>\n        /// The none\n        /// </summary>\n        none,\n\n        /// <summary>\n        /// The information\n        /// </summary>\n        info,\n\n        /// <summary>\n        /// The error\n        /// </summary>\n        error,\n\n        /// <summary>\n        /// The question\n        /// </summary>\n        question,\n\n        /// <summary>\n        /// The warning\n        /// </summary>\n        warning\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ModifierType.cs",
    "content": "﻿namespace ElectronNET.API.Entities;\n\n/// <summary>\n/// Specifies the possible modifier keys for a keyboard input (maps to InputEvent.modifiers).\n/// </summary>\n/// <remarks>Up-to-date with Electron API 39.2</remarks>\npublic enum ModifierType\n{\n    /// <summary>\n    /// The Shift key.\n    /// </summary>\n    shift,\n\n    /// <summary>\n    /// The Control key.\n    /// </summary>\n    control,\n\n    /// <summary>\n    /// The Control key (alias for control).\n    /// </summary>\n    ctrl,\n\n    /// <summary>\n    /// The Alt key.\n    /// </summary>\n    alt,\n\n    /// <summary>\n    /// The Meta key.\n    /// </summary>\n    meta,\n\n    /// <summary>\n    /// The Command key.\n    /// </summary>\n    command,\n\n    /// <summary>\n    /// The Command key (alias for command).\n    /// </summary>\n    cmd,\n\n    /// <summary>\n    /// Indicates whether the keypad modifier key is pressed.\n    /// </summary>\n    isKeypad,\n\n    /// <summary>\n    /// Indicates whether the key is an auto-repeated key.\n    /// </summary>\n    isAutoRepeat,\n\n    /// <summary>\n    /// Indicates whether the left mouse button is pressed.\n    /// </summary>\n    leftButtonDown,\n\n    /// <summary>\n    /// Indicates whether the middle mouse button is pressed.\n    /// </summary>\n    middleButtonDown,\n\n    /// <summary>\n    /// Indicates whether the right mouse button is pressed.\n    /// </summary>\n    rightButtonDown,\n\n    /// <summary>\n    /// The Caps Lock key.\n    /// </summary>\n    capsLock,\n\n    /// <summary>\n    /// The Num Lock key.\n    /// </summary>\n    numlock,\n\n    /// <summary>\n    /// The Left key.\n    /// </summary>\n    left,\n\n    /// <summary>\n    /// The Right key.\n    /// </summary>\n    right\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/NativeImage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Drawing.Drawing2D;\nusing System.Drawing.Imaging;\nusing System.IO;\nusing System.Linq;\nusing System.Text.Json.Serialization;\nusing System.Text.RegularExpressions;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Native Image handler for Electron.NET\n    /// </summary>\n    [JsonConverter(typeof(NativeImageJsonConverter))]\n    public class NativeImage\n    {\n        private readonly Dictionary<float, Image> _images = new Dictionary<float, Image>();\n        private bool _isTemplateImage;\n\n        private static readonly Dictionary<string, float> ScaleFactorPairs = new Dictionary<string, float>\n        {\n            { \"@2x\", 2.0f }, { \"@3x\", 3.0f }, { \"@1x\", 1.0f }, { \"@4x\", 4.0f },\n            { \"@5x\", 5.0f }, { \"@1.25x\", 1.25f }, { \"@1.33x\", 1.33f }, { \"@1.4x\", 1.4f },\n            { \"@1.5x\", 1.5f }, { \"@1.8x\", 1.8f }, { \"@2.5x\", 2.5f }\n        };\n\n        private static float? ExtractDpiFromFilePath(string filePath)\n        {\n            var withoutExtension = Path.GetFileNameWithoutExtension(filePath);\n            return ScaleFactorPairs\n                .Where(p => withoutExtension.EndsWith(p.Key))\n                .Select(p => p.Value)\n                .FirstOrDefault();\n        }\n\n        private static Image BytesToImage(byte[] bytes)\n        {\n            var ms = new MemoryStream(bytes);\n            return Image.FromStream(ms);\n        }\n\n        /// <summary>\n        /// Creates an empty NativeImage\n        /// </summary>\n        public static NativeImage CreateEmpty()\n        {\n            return new NativeImage();\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public static NativeImage CreateFromBitmap(Bitmap bitmap, CreateFromBitmapOptions options = null)\n        {\n            if (options is null)\n            {\n                options = new CreateFromBitmapOptions();\n            }\n\n            return new NativeImage(bitmap, options.ScaleFactor);\n        }\n\n        /// <summary>\n        /// Creates a NativeImage from a byte array.\n        /// </summary>\n        public static NativeImage CreateFromBuffer(byte[] buffer, CreateFromBufferOptions options = null)\n        {\n            if (options is null)\n            {\n                options = new CreateFromBufferOptions();\n            }\n\n            var ms = new MemoryStream(buffer);\n            var image = Image.FromStream(ms);\n\n            return new NativeImage(image, options.ScaleFactor);\n        }\n\n        /// <summary>\n        /// Creates a NativeImage from a base64 encoded data URL.\n        /// </summary>\n        /// <param name=\"dataUrl\">A data URL with a base64 encoded image.</param>\n        public static NativeImage CreateFromDataURL(string dataUrl)\n        {\n            var images = new Dictionary<float, Image>();\n            var parsedDataUrl = Regex.Match(dataUrl, @\"data:image/(?<type>.+?),(?<data>.+)\");\n            var actualData = parsedDataUrl.Groups[\"data\"].Value;\n            var binData = Convert.FromBase64String(actualData);\n\n            var image = BytesToImage(binData);\n\n            images.Add(1.0f, image);\n\n            return new NativeImage(images);\n        }\n\n        /// <summary>\n        /// Creates a NativeImage from an image on the disk.\n        /// </summary>\n        /// <param name=\"path\">The path of the image</param>\n        public static NativeImage CreateFromPath(string path)\n        {\n            var images = new Dictionary<float, Image>();\n            if (Regex.IsMatch(path, \"(@.+?x)\"))\n            {\n                var dpi = ExtractDpiFromFilePath(path);\n                if (dpi == null)\n                {\n                    throw new Exception($\"Invalid scaling factor for '{path}'.\");\n                }\n\n                images[dpi.Value] = Image.FromFile(path);\n            }\n            else\n            {\n                var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);\n                var extension = Path.GetExtension(path);\n                // Load as 1x dpi\n                images[1.0f] = Image.FromFile(path);\n\n                foreach (var scale in ScaleFactorPairs)\n                {\n                    var fileName = $\"{fileNameWithoutExtension}{scale}.{extension}\";\n                    if (File.Exists(fileName))\n                    {\n                        var dpi = ExtractDpiFromFilePath(fileName);\n                        if (dpi != null)\n                        {\n                            images[dpi.Value] = Image.FromFile(fileName);\n                        }\n                    }\n                }\n            }\n\n            return new NativeImage(images);\n        }\n\n        /// <summary>\n        /// Creates an empty NativeImage\n        /// </summary>\n        public NativeImage()\n        {\n        }\n\n        /// <summary>\n        /// Creates a NativeImage from a bitmap and scale factor\n        /// </summary>\n        public NativeImage(Image bitmap, float scaleFactor = 1.0f)\n        {\n            _images.Add(scaleFactor, bitmap);\n        }\n\n        /// <summary>\n        /// Creates a NativeImage from a dictionary of scales and images.\n        /// </summary>\n        public NativeImage(Dictionary<float, Image> imageDictionary)\n        {\n            _images = imageDictionary;\n        }\n\n        /// <summary>\n        /// Crops the image specified by the input rectangle and computes scale factor\n        /// </summary>\n        public NativeImage Crop(Rectangle rect)\n        {\n            var images = new Dictionary<float, Image>();\n            foreach (var image in _images)\n            {\n                images.Add(image.Key, Crop(rect.X, rect.Y, rect.Width, rect.Height, image.Key));\n            }\n\n            return new NativeImage(images);\n        }\n\n        /// <summary>\n        /// Resizes the image and computes scale factor\n        /// </summary>\n        public NativeImage Resize(ResizeOptions options)\n        {\n            var images = new Dictionary<float, Image>();\n            foreach (var image in _images)\n            {\n                images.Add(image.Key, Resize(options.Width, options.Height, image.Key));\n            }\n\n            return new NativeImage(images);\n        }\n\n        /// <summary>\n        /// Add an image representation for a specific scale factor.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        public void AddRepresentation(AddRepresentationOptions options)\n        {\n            if (options.Buffer.Length > 0)\n            {\n                _images[options.ScaleFactor] =\n                    CreateFromBuffer(options.Buffer, new CreateFromBufferOptions { ScaleFactor = options.ScaleFactor })\n                        .GetScale(options.ScaleFactor);\n            }\n            else if (!string.IsNullOrEmpty(options.DataUrl))\n            {\n                _images[options.ScaleFactor] = CreateFromDataURL(options.DataUrl).GetScale(options.ScaleFactor);\n            }\n        }\n\n        /// <summary>\n        /// Gets the aspect ratio for the image based on scale factor\n        /// </summary>\n        /// <param name=\"scaleFactor\">Optional</param>\n        public float GetAspectRatio(float scaleFactor = 1.0f)\n        {\n            var image = GetScale(scaleFactor);\n            if (image != null)\n            {\n                return image.Width / image.Height;\n            }\n\n            return 0f;\n        }\n\n        /// <summary>\n        /// Returns a byte array that contains the image's raw bitmap pixel data.\n        /// </summary>\n        public byte[] GetBitmap(BitmapOptions options)\n        {\n            return ToBitmap(new ToBitmapOptions { ScaleFactor = options.ScaleFactor });\n        }\n\n        /// <summary>\n        /// Returns a byte array that contains the image's raw bitmap pixel data.\n        /// </summary>\n        public byte[] GetNativeHandle()\n        {\n            return ToBitmap(new ToBitmapOptions());\n        }\n\n        /// <summary>\n        /// Gets the size of the specified image based on scale factor\n        /// </summary>\n        public Size GetSize(float scaleFactor = 1.0f)\n        {\n            if (_images.ContainsKey(scaleFactor))\n            {\n                var image = _images[scaleFactor];\n                return new Size\n                {\n                    Width = image.Width,\n                    Height = image.Height\n                };\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Checks to see if the NativeImage instance is empty.\n        /// </summary>\n        public bool IsEmpty()\n        {\n            return _images.Count <= 0;\n        }\n\n        /// <summary>\n        /// Deprecated. Whether the image is a template image.\n        /// </summary>\n        public bool IsTemplateImage => _isTemplateImage;\n\n        /// <summary>\n        /// Whether the image is considered a macOS template image.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool IsMacTemplateImage => _isTemplateImage;\n\n        /// <summary>\n        /// Deprecated. Marks the image as a template image.\n        /// </summary>\n        public void SetTemplateImage(bool option)\n        {\n            _isTemplateImage = option;\n        }\n\n        /// <summary>\n        /// Outputs a bitmap based on the scale factor\n        /// </summary>\n        public byte[] ToBitmap(ToBitmapOptions options)\n        {\n            return ImageToBytes(ImageFormat.Bmp, options.ScaleFactor);\n        }\n\n        /// <summary>\n        /// Outputs a data URL based on the scale factor\n        /// </summary>\n        public string ToDataURL(ToDataUrlOptions options)\n        {\n            if (!_images.ContainsKey(options.ScaleFactor))\n            {\n                return null;\n            }\n\n            var image = _images[options.ScaleFactor];\n            var mimeType = ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == image.RawFormat.Guid)?.MimeType;\n            if (mimeType is null)\n            {\n                mimeType = \"image/png\";\n            }\n\n            var bytes = ImageToBytes(image.RawFormat, options.ScaleFactor);\n            var base64 = Convert.ToBase64String(bytes);\n\n            return $\"data:{mimeType};base64,{base64}\";\n        }\n\n        /// <summary>\n        /// Outputs a JPEG for the default scale factor\n        /// </summary>\n        public byte[] ToJPEG(int quality)\n        {\n            return ImageToBytes(ImageFormat.Jpeg, 1.0f, quality);\n        }\n\n        /// <summary>\n        /// Outputs a PNG for the specified scale factor\n        /// </summary>\n        public byte[] ToPNG(ToPNGOptions options)\n        {\n            return ImageToBytes(ImageFormat.Png, options.ScaleFactor);\n        }\n\n        private byte[] ImageToBytes(ImageFormat imageFormat = null, float scaleFactor = 1.0f, int quality = 100)\n        {\n            using var ms = new MemoryStream();\n\n            if (_images.ContainsKey(scaleFactor))\n            {\n                var image = _images[scaleFactor];\n                var encoderCodecInfo = GetEncoder(imageFormat ?? image.RawFormat);\n                var encoder = Encoder.Quality;\n\n                var encoderParameters = new EncoderParameters(1)\n                {\n                    Param = new[]\n                    {\n                        new EncoderParameter(encoder, quality)\n                    }\n                };\n\n                image.Save(ms, encoderCodecInfo, encoderParameters);\n\n                return ms.ToArray();\n            }\n\n            return null;\n        }\n\n        private Image Resize(int? width, int? height, float scaleFactor = 1.0f)\n        {\n            if (!_images.ContainsKey(scaleFactor) || (width is null && height is null))\n            {\n                return null;\n            }\n\n            var image = _images[scaleFactor];\n            using (var g = Graphics.FromImage(image))\n            {\n                g.CompositingQuality = CompositingQuality.HighQuality;\n\n                var aspect = GetAspectRatio(scaleFactor);\n\n                width ??= Convert.ToInt32(image.Width * aspect);\n                height ??= Convert.ToInt32(image.Height * aspect);\n\n                width = Convert.ToInt32(width * scaleFactor);\n                height = Convert.ToInt32(height * scaleFactor);\n\n                var bmp = new Bitmap(width.Value, height.Value);\n                g.DrawImage(bmp,\n                    new System.Drawing.Rectangle(0, 0, image.Width, image.Height),\n                    new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),\n                    GraphicsUnit.Pixel);\n\n                return bmp;\n            }\n        }\n\n        private Image Crop(int? x, int? y, int? width, int? height, float scaleFactor = 1.0f)\n        {\n            if (!_images.ContainsKey(scaleFactor))\n            {\n                return null;\n            }\n\n            var image = _images[scaleFactor];\n            using (var g = Graphics.FromImage(image))\n            {\n                g.CompositingQuality = CompositingQuality.HighQuality;\n\n                x ??= 0;\n                y ??= 0;\n\n                x = Convert.ToInt32(x * scaleFactor);\n                y = Convert.ToInt32(y * scaleFactor);\n\n                width ??= image.Width;\n                height ??= image.Height;\n\n                width = Convert.ToInt32(width * scaleFactor);\n                height = Convert.ToInt32(height * scaleFactor);\n\n                var bmp = new Bitmap(width.Value, height.Value);\n                g.DrawImage(bmp, new System.Drawing.Rectangle(0, 0, image.Width, image.Height), new System.Drawing.Rectangle(x.Value, y.Value, width.Value, height.Value), GraphicsUnit.Pixel);\n\n                return bmp;\n            }\n        }\n\n        private ImageCodecInfo GetEncoder(ImageFormat format)\n        {\n            var codecs = ImageCodecInfo.GetImageDecoders();\n            foreach (ImageCodecInfo codec in codecs)\n            {\n                if (codec.FormatID == format.Guid)\n                {\n                    return codec;\n                }\n            }\n\n            return null;\n        }\n\n        internal Dictionary<float, string> GetAllScaledImages()\n        {\n            var dict = new Dictionary<float, string>();\n            try\n            {\n                foreach (var (scale, image) in _images)\n                {\n                    dict.Add(scale, Convert.ToBase64String(ImageToBytes(null, scale)));\n                }\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine(ex);\n            }\n\n            return dict;\n        }\n\n        internal Image GetScale(float scaleFactor)\n        {\n            if (_images.ContainsKey(scaleFactor))\n            {\n                return _images[scaleFactor];\n            }\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/NativeImageJsonConverter.cs",
    "content": "using ElectronNET.API.Serialization;\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.IO;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <yremarks>Project-specific: JSON converter for NativeImage; no MCP structure equivalent.</yremarks>\n    internal class NativeImageJsonConverter : JsonConverter<NativeImage>\n    {\n        public override void Write(Utf8JsonWriter writer, NativeImage value, JsonSerializerOptions options)\n        {\n            if (value is null)\n            {\n                writer.WriteNullValue();\n                return;\n            }\n\n            var scaledImages = value.GetAllScaledImages();\n            JsonSerializer.Serialize(writer, scaledImages, ElectronJson.Options);\n        }\n\n        public override NativeImage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n        {\n            var dict = JsonSerializer.Deserialize<Dictionary<float, string>>(ref reader, ElectronJson.Options);\n            var newDictionary = new Dictionary<float, Image>();\n            foreach (var item in dict)\n            {\n                var bytes = Convert.FromBase64String(item.Value);\n                newDictionary.Add(item.Key, Image.FromStream(new MemoryStream(bytes)));\n            }\n\n            return new NativeImage(newDictionary);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/NotificationAction.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"macos\")]\n    public class NotificationAction\n    {\n        /// <summary>\n        /// Gets or sets the label for the action.\n        /// </summary>\n        public string Text { get; set; }\n\n        /// <summary>\n        /// Gets or sets the type of action; can be 'button'.\n        /// </summary>\n        public string Type { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/NotificationOptions.cs",
    "content": "using System;\nusing System.Runtime.Versioning;\nusing System.Text.Json.Serialization;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class NotificationOptions\n    {\n        /// <summary>\n        /// Gets or sets the title for the notification, which will be shown at the top of the notification window when it is shown.\n        /// </summary>\n        public string Title { get; set; }\n\n        /// <summary>\n        /// Gets or sets the subtitle for the notification, which will be displayed below the title.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [JsonPropertyName(\"subtitle\")]\n        public string Subtitle { get; set; }\n\n        /// <summary>\n        /// Gets or sets the body text of the notification, which will be displayed below the title or subtitle.\n        /// </summary>\n        public string Body { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to suppress the OS notification noise when showing the notification.\n        /// </summary>\n        public bool Silent { get; set; }\n\n        /// <summary>\n        /// Gets or sets an icon to use in the notification. Can be a string path or a NativeImage. If a string is passed, it must be a valid path to a local icon file.\n        /// </summary>\n        public string Icon { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to add an inline reply option to the notification.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool HasReply { get; set; }\n\n        /// <summary>\n        /// Gets or sets the timeout duration of the notification. Can be 'default' or 'never'.\n        /// </summary>\n        [SupportedOSPlatform(\"linux\")]\n        [SupportedOSPlatform(\"windows\")]\n        public string TimeoutType { get; set; }\n\n        /// <summary>\n        /// Gets or sets the placeholder to write in the inline reply input field.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string ReplyPlaceholder { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name of the sound file to play when the notification is shown.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string Sound { get; set; }\n\n        /// <summary>\n        /// Gets or sets the urgency level of the notification. Can be 'normal', 'critical', or 'low'.\n        /// </summary>\n        [SupportedOSPlatform(\"linux\")]\n        public string Urgency { get; set; }\n\n        /// <summary>\n        /// Gets or sets the actions to add to the notification. Please read the available actions and limitations in the NotificationAction documentation.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public NotificationAction[] Actions { get; set; }\n\n        /// <summary>\n        /// Gets or sets a custom title for the close button of an alert. An empty string will cause the default localized text to be used.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string CloseButtonText { get; set; }\n\n        /// <summary>\n        /// Gets or sets a custom description of the Notification on Windows superseding all properties above. Provides full customization of design and behavior of the notification.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string ToastXml { get; set; }\n\n        /// <summary>\n        /// Emitted when the notification is shown to the user, note this could be fired\n        /// multiple times as a notification can be shown multiple times through the Show()\n        /// method.\n        /// </summary>\n        [JsonIgnore]\n        public Action OnShow { get; set; }\n\n        /// <summary>\n        /// Gets or sets the show identifier.\n        /// </summary>\n        /// <value>\n        /// The show identifier.\n        /// </value>\n        [JsonInclude]\n        internal string ShowID { get; set; }\n\n        /// <summary>\n        /// Emitted when the notification is clicked by the user.\n        /// </summary>\n        [JsonIgnore]\n        public Action OnClick { get; set; }\n\n        /// <summary>\n        /// Gets or sets the click identifier.\n        /// </summary>\n        /// <value>\n        /// The click identifier.\n        /// </value>\n        [JsonInclude]\n        internal string ClickID { get; set; }\n\n        /// <summary>\n        /// Emitted when the notification is closed by manual intervention from the user.\n        ///\n        /// This event is not guarunteed to be emitted in all cases where the notification is closed.\n        /// </summary>\n        [JsonIgnore]\n        public Action OnClose { get; set; }\n\n        /// <summary>\n        /// Gets or sets the close identifier.\n        /// </summary>\n        /// <value>\n        /// The close identifier.\n        /// </value>\n        [JsonInclude]\n        internal string CloseID { get; set; }\n\n        /// <summary>\n        /// macOS only: Emitted when the user clicks the “Reply” button on a notification with hasReply: true.\n        /// \n        /// The string the user entered into the inline reply field\n        /// </summary>\n        [JsonIgnore]\n        [SupportedOSPlatform(\"macos\")]\n        public Action<string> OnReply { get; set; }\n\n        /// <summary>\n        /// Gets or sets the reply identifier.\n        /// </summary>\n        /// <value>\n        /// The reply identifier.\n        /// </value>\n        [JsonInclude]\n        internal string ReplyID { get; set; }\n\n        /// <summary>\n        /// macOS only - The index of the action that was activated.\n        /// </summary>\n        [JsonIgnore]\n        [SupportedOSPlatform(\"macos\")]\n        public Action<int> OnAction { get; set; }\n\n        /// <summary>\n        /// Gets or sets the action identifier.\n        /// </summary>\n        /// <value>\n        /// The action identifier.\n        /// </value>\n        [JsonInclude]\n        internal string ActionID { get; set; }\n\n        /// <summary>\n        /// Windows only: Emitted when an error is encountered while creating and showing the native notification.\n        /// Corresponds to the 'failed' event on Notification.\n        /// </summary>\n        [JsonIgnore]\n        [SupportedOSPlatform(\"windows\")]\n        public Action<string> OnFailed { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"NotificationOptions\"/> class.\n        /// </summary>\n        /// <param name=\"title\">The title.</param>\n        /// <param name=\"body\">The body.</param>\n        public NotificationOptions(string title, string body)\n        {\n            Title = title;\n            Body = body;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/OnDidFailLoadInfo.cs",
    "content": "﻿namespace ElectronNET.API.Entities;\n\n/// <summary>\n/// 'OnDidFailLoad' event details.\n/// </summary>\npublic class OnDidFailLoadInfo\n{\n    /// <summary>\n    /// The full list of error codes and their meaning is available here\n    /// https://source.chromium.org/chromium/chromium/src/+/main:net/base/net_error_list.h\n    /// </summary>\n    public int ErrorCode { get; set; }\n\n    /// <summary>\n    /// Validated URL.\n    /// </summary>\n    public string ValidatedUrl { get; set; }\n\n    /// <summary>\n    /// Error description string.\n    /// </summary>\n    public string ErrorDescription { get; set; }\n\n    /// <summary>\n    /// True if the event pertains to the main frame.\n    /// </summary>\n    public bool IsMainFrame { get; set; }\n\n    /// <summary>\n    /// The process id for the frame.\n    /// </summary>\n    public int FrameProcessId { get; set; }\n\n    /// <summary>\n    /// The routing id for the frame.\n    /// </summary>\n    public int FrameRoutingId { get; set; }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/OnDidNavigateInfo.cs",
    "content": "﻿namespace ElectronNET.API.Entities;\n\n/// <summary>\n/// 'did-navigate' event details for main frame navigation.\n/// </summary>\n/// <remarks>Up-to-date with Electron API 39.2</remarks>\npublic class OnDidNavigateInfo\n{\n    /// <summary>\n    /// The URL navigated to.\n    /// </summary>\n    public string Url { get; set; }\n\n    /// <summary>\n    /// HTTP response code (-1 for non-HTTP navigations).\n    /// </summary>\n    public int HttpResponseCode { get; set; }\n\n    /// <summary>\n    /// HTTP status text (empty for non-HTTP navigations).\n    /// </summary>\n    public string HttpStatusText { get; set; }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/OnTopLevel.cs",
    "content": "﻿using System.ComponentModel;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// String values for the 'level' parameter of BrowserWindow.setAlwaysOnTop.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public enum OnTopLevel\n    {\n        /// <summary>\n        /// The normal\n        /// </summary>\n        normal,\n\n        /// <summary>\n        /// The floating\n        /// </summary>\n        floating,\n\n        /// <summary>\n        /// The torn off menu\n        /// </summary>\n        [Description(\"torn-off-menu\")]\n        tornOffMenu,\n\n        /// <summary>\n        /// The modal panel\n        /// </summary>\n        [Description(\"modal-panel\")]\n        modalPanel,\n\n        /// <summary>\n        /// The main menu\n        /// </summary>\n        [Description(\"main-menu\")]\n        mainMenu,\n\n        /// <summary>\n        /// The status\n        /// </summary>\n        status,\n\n        /// <summary>\n        /// The pop up menu\n        /// </summary>\n        [Description(\"pop-up-menu\")]\n        popUpMenu,\n\n        /// <summary>\n        /// The screen saver\n        /// </summary>\n        [Description(\"screen-saver\")]\n        screenSaver\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/OpenDevToolsOptions.cs",
    "content": "using System.Text.Json.Serialization;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public class OpenDevToolsOptions\n    {\n        /// <summary>\n        /// Opens the DevTools with specified dock state. Can be left, right, bottom, undocked, or detach.\n        /// Defaults to the last used dock state. In undocked mode it's possible to dock back; in detach mode it's not.\n        /// </summary>\n        public DevToolsMode Mode { get; set; }\n\n        /// <summary>\n        /// Whether to bring the opened DevTools window to the foreground. Default is true.\n        /// </summary>\n        public bool Activate { get; set; } = true;\n\n        /// <summary>\n        /// A title for the DevTools window (only visible in undocked or detach mode).\n        /// </summary>\n        public string Title { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/OpenDialogOptions.cs",
    "content": "using System.Text.Json.Serialization;\n\nnamespace ElectronNET.API.Entities\n{\n    using System.Runtime.Versioning;\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class OpenDialogOptions\n    {\n        /// <summary>\n        /// Gets or sets the title.\n        /// </summary>\n        /// <value>\n        /// The title.\n        /// </value>\n        public string Title { get; set; }\n\n        /// <summary>\n        /// Gets or sets the default path.\n        /// </summary>\n        /// <value>\n        /// The default path.\n        /// </value>\n        public string DefaultPath { get; set; }\n\n        /// <summary>\n        /// Custom label for the confirmation button, when left empty the default label will be used.\n        /// </summary>\n        public string ButtonLabel { get; set; }\n\n        /// <summary>\n        /// Gets or sets which features the dialog should use. The following values are supported:\n        /// 'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory'\n        /// </summary>\n        public OpenDialogProperty[] Properties { get; set; }\n\n        /// <summary>\n        /// Gets or sets the message to display above input boxes.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string Message { get; set; }\n\n        /// <summary>\n        /// Gets or sets the filters specifying an array of file types that can be displayed or\n        /// selected when you want to limit the user to a specific type. For example:\n        /// </summary>\n        /// <example>\n        /// <code>\n        /// new FileFilter[]\n        /// {\n        ///  new FileFiler { Name = \"Images\", Extensions = new string[] { \"jpg\", \"png\", \"gif\" } },\n        ///  new FileFiler { Name = \"Movies\", Extensions = new string[] { \"mkv\", \"avi\", \"mp4\" } },\n        ///  new FileFiler { Name = \"Custom File Type\", Extensions= new string[] {\"as\" } },\n        ///  new FileFiler { Name = \"All Files\", Extensions= new string[] { \"*\" } }\n        /// }\n        /// </code>\n        /// </example>\n        public FileFilter[] Filters { get; set; }\n\n        /// <summary>\n        /// Create security scoped bookmarks when packaged for the Mac App Store.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool SecurityScopedBookmarks { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/OpenDialogProperty.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    using System.Runtime.Versioning;\n\n    /// <summary>\n    /// \n    /// </summary>\n    public enum OpenDialogProperty\n    {\n        /// <summary>\n        /// The open file\n        /// </summary>\n        openFile,\n\n        /// <summary>\n        /// The open directory\n        /// </summary>\n        openDirectory,\n\n        /// <summary>\n        /// The multi selections\n        /// </summary>\n        multiSelections,\n\n        /// <summary>\n        /// The show hidden files\n        /// </summary>\n        showHiddenFiles,\n\n        /// <summary>\n        /// The create directory\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        createDirectory,\n\n        /// <summary>\n        /// The prompt to create\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        promptToCreate,\n\n        /// <summary>\n        /// The no resolve aliases\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        noResolveAliases,\n\n        /// <summary>\n        /// The treat package as directory\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        treatPackageAsDirectory,\n\n        /// <summary>\n        /// Do not add the item being opened to the recent documents list (Windows).\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        dontAddToRecent\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/OpenExternalOptions.cs",
    "content": "﻿using System.ComponentModel;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Controls the behavior of OpenExternal.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class OpenExternalOptions\n    {\n        /// <summary>\n        /// Gets or sets whether to bring the opened application to the foreground. The default is <see langword=\"true\"/>.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [DefaultValue(true)]\n        public bool Activate { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets the working directory.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string WorkingDirectory { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating a user-initiated launch that enables tracking of frequently used programs and other behaviors. The default is <see langword=\"false\"/>.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        [DefaultValue(false)]\n        public bool LogUsage { get; set; } = false;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/PageSize.cs",
    "content": "﻿namespace ElectronNET.API.Entities;\n\npublic class PageSize\n{\n    private readonly string _value;\n\n    /// <summary>\n    /// Represents the page size for printing/PDF.\n    /// Matches Electron semantics: either a named size (e.g. 'A4', 'Letter', 'Legal', 'Tabloid', 'Ledger', etc.)\n    /// or a custom size specified by Height and Width in inches.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public PageSize()\n    {\n    }\n\n    private PageSize(string value) : this() => _value = value;\n\n    /// <summary>\n    /// Gets or sets the custom page height in inches (when using object form instead of a named size).\n    /// </summary>\n    public double Height { get; set; }\n\n    /// <summary>\n    /// Gets or sets the custom page width in inches (when using object form instead of a named size).\n    /// </summary>\n    public double Width { get; set; }\n\n    /// <summary>\n    /// Implicit conversion to string to represent named page sizes (e.g. 'A4', 'Letter').\n    /// </summary>\n    public static implicit operator string(PageSize pageSize) => pageSize?._value;\n\n    /// <summary>\n    /// Implicit conversion from string to represent named page sizes (e.g. 'A4', 'Letter').\n    /// </summary>\n    public static implicit operator PageSize(string value) => new(value);\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/PathName.cs",
    "content": "﻿using System.ComponentModel;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Names for app.getPath(name). Aligned with Electron docs.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public enum PathName\n    {\n        /// <summary>\n        /// User's home directory.\n        /// </summary>\n        Home,\n\n        /// <summary>\n        /// Per-user application data directory.\n        /// </summary>\n        AppData,\n\n        /// <summary>\n        /// The directory for storing your app's configuration files, which by default is the appData directory appended with your app's name.\n        /// </summary>\n        UserData,\n\n        /// <summary>\n        /// The directory for storing data generated by Session, such as localStorage, cookies, disk cache, downloaded dictionaries, network state, devtools files.\n        /// By default this points to userData.\n        /// </summary>\n        SessionData,\n\n        /// <summary>\n        /// Temporary directory.\n        /// </summary>\n        Temp,\n\n        /// <summary>\n        /// The current executable file.\n        /// </summary>\n        Exe,\n\n        /// <summary>\n        /// The location of the Chromium module. By default this is synonymous with exe.\n        /// </summary>\n        Module,\n\n        /// <summary>\n        /// The current user's Desktop directory.\n        /// </summary>\n        Desktop,\n\n        /// <summary>\n        /// Directory for a user's \"My Documents\".\n        /// </summary>\n        Documents,\n\n        /// <summary>\n        /// Directory for a user's downloads.\n        /// </summary>\n        Downloads,\n\n        /// <summary>\n        /// Directory for a user's music.\n        /// </summary>\n        Music,\n\n        /// <summary>\n        /// Directory for a user's pictures.\n        /// </summary>\n        Pictures,\n\n        /// <summary>\n        /// Directory for a user's videos.\n        /// </summary>\n        Videos,\n\n        /// <summary>\n        /// Directory for the user's recent files. Windows only.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        Recent,\n\n        /// <summary>\n        /// Directory for your app's log folder.\n        /// </summary>\n        Logs,\n\n        /// <summary>\n        /// Directory where crash dumps are stored.\n        /// </summary>\n        CrashDumps,\n\n        /// <summary>\n        /// The directory where app assets such as resources.pak are stored.\n        /// Available on Windows and Linux only.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        [SupportedOSPlatform(\"linux\")]\n        Assets\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Point.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class Point\n    {\n        /// <summary>\n        /// Gets or sets the x.\n        /// </summary>\n        /// <value>\n        /// The x.\n        /// </value>\n        public int X { get; set; }\n\n        /// <summary>\n        /// Gets or sets the y.\n        /// </summary>\n        /// <value>\n        /// The y.\n        /// </value>\n        public int Y { get; set; }\n\n        /// <summary>\n        /// Convert this <see cref=\"Point\"/> to <see cref=\"System.Drawing.Point\"/>.\n        /// </summary>\n        /// <param name=\"point\">The point.</param>\n        public static implicit operator System.Drawing.Point(Point point)\n        {\n            return new System.Drawing.Point(point.X, point.Y);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/PrintOptions.cs",
    "content": "namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Print dpi\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class PrintDpi\n    {\n        /// <summary>\n        /// Gets or sets the horizontal DPI.\n        /// </summary>\n        public float Horizontal { get; set; }\n\n        /// <summary>\n        /// Gets or sets the vertical DPI.\n        /// </summary>\n        public float Vertical { get; set; }\n    }\n\n    /// <summary>\n    /// The page range to print\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class PrintPageRange\n    {\n        /// <summary>\n        /// Gets or sets the starting page index (0-based).\n        /// </summary>\n        public int From { get; set; }\n\n        /// <summary>\n        /// Gets or sets the ending page index (inclusive, 0-based).\n        /// </summary>\n        public int To { get; set; }\n    }\n\n    /// <summary>\n    /// Print options\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class PrintOptions\n    {\n        /// <summary>\n        /// Gets or sets a value indicating whether to suppress print settings prompts.\n        /// </summary>\n        public bool Silent { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to print background graphics.\n        /// </summary>\n        public bool PrintBackground { get; set; }\n\n        /// <summary>\n        /// Gets or sets the printer device name to use.\n        /// </summary>\n        public string DeviceName { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the page will be printed in color.\n        /// </summary>\n        public bool Color { get; set; }\n\n        /// <summary>\n        /// Gets or sets the margins for the print job. Use MarginType plus top/bottom/left/right for custom.\n        /// Units for margins with webContents.print are pixels (per MCP); for webContents.printToPDF, inches.\n        /// </summary>\n        public Margins Margins { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to print in landscape orientation.\n        /// </summary>\n        public bool Landscape { get; set; }\n\n        /// <summary>\n        /// Gets or sets the scale factor of the web page.\n        /// </summary>\n        public float ScaleFactor { get; set; }\n\n        /// <summary>\n        /// Gets or sets the number of pages to print per sheet.\n        /// </summary>\n        public int PagesPerSheet { get; set; }\n\n        /// <summary>\n        /// Gets or sets the number of copies to print.\n        /// </summary>\n        public int Copies { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether pages should be collated.\n        /// </summary>\n        public bool Collate { get; set; }\n\n        /// <summary>\n        /// Gets or sets the page range(s) to print. On macOS, only one range is honored.\n        /// </summary>\n        public PrintPageRange[] PageRanges { get; set; }\n\n        /// <summary>\n        /// Gets or sets the duplex mode of the printed web page. Can be simplex, shortEdge, or longEdge.\n        /// </summary>\n        public string DuplexMode { get; set; }\n\n        /// <summary>\n        /// Gets or sets the DPI settings for the print job.\n        /// </summary>\n        public PrintDpi Dpi { get; set; }\n\n        /// <summary>\n        /// Gets or sets the string to be printed as page header.\n        /// </summary>\n        public string Header { get; set; }\n\n        /// <summary>\n        /// Gets or sets the string to be printed as page footer.\n        /// </summary>\n        public string Footer { get; set; }\n\n        /// <summary>\n        /// Gets or sets the page size of the printed document. Can be A0–A6, Legal, Letter, Tabloid,\n        /// or an object. For webContents.print, custom sizes use microns (Chromium validates width_microns/height_microns).\n        /// </summary>\n        public PageSize PageSize { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/PrintToPDFOptions.cs",
    "content": "using ElectronNET.Converter;\nusing System.Text.Json.Serialization;\n\nnamespace ElectronNET.API.Entities;\n\n/// <summary>\n/// \n/// </summary>\n/// <remarks>Up-to-date with Electron API 39.2</remarks>\npublic class PrintToPDFOptions\n{\n    /// <summary>\n    /// Gets or sets the paper orientation. `true` for landscape, `false` for portrait. Defaults to false.\n    /// </summary>\n    public bool Landscape { get; set; } = false;\n\n    /// <summary>\n    /// Gets or sets whether to display header and footer. Defaults to false.\n    /// </summary>\n    public bool DisplayHeaderFooter { get; set; } = false;\n\n    /// <summary>\n    /// Gets or sets whether to print background graphics. Defaults to false.\n    /// </summary>\n    public bool PrintBackground { get; set; } = false;\n\n    /// <summary>\n    /// Gets or sets the scale of the webpage rendering. Defaults to 1.\n    /// </summary>\n    public double Scale { get; set; } = 1;\n\n    /// <summary>\n    /// Gets or sets the page size of the generated PDF. Can be `A0`, `A1`, `A2`, `A3`, `A4`,\n    /// `A5`, `A6`, `Legal`, `Letter`, `Tabloid`, `Ledger`, or an Object containing\n    /// `height` and `width` in inches. Defaults to `Letter`.\n    /// </summary>\n    [JsonConverter(typeof(PageSizeConverter))]\n    public PageSize PageSize { get; set; } = \"Letter\";\n\n    /// <summary>\n    /// Gets or sets the paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string,\n    /// which means print all pages.\n    /// </summary>\n    public string PageRanges { get; set; } = \"\";\n\n    /// <summary>\n    /// Gets or sets the HTML template for the print header. Should be valid HTML markup with following\n    /// classes used to inject printing values into them: `date` (formatted print date),\n    /// `title` (document title), `url` (document location), `pageNumber` (current page\n    /// number) and `totalPages` (total pages in the document). For example, `<span class=\"title\"></span>`\n    /// would generate span containing the title.\n    /// </summary>\n    public string HeaderTemplate { get; set; }\n\n    /// <summary>\n    /// Gets or sets the HTML template for the print footer. Should use the same format as the\n    /// `headerTemplate`.\n    /// </summary>\n    public string FooterTemplate { get; set; }\n\n    /// <summary>\n    /// Gets or sets whether to prefer page size as defined by css. Defaults to false, in\n    /// which case the content will be scaled to fit the paper size.\n    /// </summary>\n    public bool PreferCSSPageSize { get; set; } = false;\n\n    /// <summary>\n    /// Gets or sets whether to generate a tagged (accessible) PDF. Defaults to false.\n    /// Experimental per Electron docs; the generated PDF may not adhere fully to PDF/UA and WCAG standards.\n    /// </summary>\n    public bool GenerateTaggedPDF { get; set; } = false;\n\n    /// <summary>\n    /// Gets or sets whether to generate a PDF document outline from content headers. Defaults to false.\n    /// Experimental per Electron docs.\n    /// </summary>\n    public bool GenerateDocumentOutline { get; set; } = false;\n\n    public Margins Margins { get; set; }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/PrinterInfo.cs",
    "content": "using System.Collections.Generic;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// PrinterInfo structure as returned by webContents.getPrintersAsync(). Fields backed by MCP: name, displayName, description, options.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class PrinterInfo\n    {\n        /// <summary>\n        /// Gets or sets the name of the printer as understood by the OS.\n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name of the printer as shown in Print Preview.\n        /// </summary>\n        public string DisplayName { get; set; }\n\n        /// <summary>\n        /// Gets or sets a longer description of the printer's type.\n        /// </summary>\n        public string Description { get; set; }\n\n        /// <summary>\n        /// Gets or sets the status code reported by the OS. Semantics are platform-specific.\n        /// Not MCP-backed: this field is not listed in Electron's PrinterInfo structure.\n        /// </summary>\n        public int Status { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this printer is the system default.\n        /// Not MCP-backed: this field is not listed in Electron's PrinterInfo structure.\n        /// </summary>\n        public bool IsDefault { get; set; }\n\n        /// <summary>\n        /// Gets or sets the platform-specific printer information as an object (keys/values vary by OS).\n        /// </summary>\n        public Dictionary<string, string> Options { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ProcessMetric.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Process metrics information.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class ProcessMetric\n    {\n        /// <summary>\n        /// Gets or sets the process id of the process.\n        /// </summary>\n        public int PId { get; set; }\n\n        /// <summary>\n        /// Gets or sets the process type. One of: Browser | Tab | Utility | Zygote | Sandbox helper | GPU | Pepper Plugin | Pepper Plugin Broker | Unknown.\n        /// </summary>\n        public string Type { get; set; }\n\n        /// <summary>\n        /// Gets or sets the CPU usage of the process.\n        /// </summary>\n        public CPUUsage Cpu { get; set; }\n\n        /// <summary>\n        /// Gets or sets the creation time for this process, represented as the number of milliseconds since the UNIX epoch. Since the pid can be reused after a process dies, use both pid and creationTime to uniquely identify a process.\n        /// </summary>\n        public double CreationTime { get; set; }\n\n        /// <summary>\n        /// Gets or sets the memory information for the process.\n        /// </summary>\n        public MemoryInfo Memory { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the process is sandboxed on OS level.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        [SupportedOSPlatform(\"windows\")]\n        public bool Sandboxed { get; set; }\n\n        /// <summary>\n        /// Gets or sets the integrity level. One of: untrusted | low | medium | high | unknown.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string IntegrityLevel { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name of the process. Examples for utility: Audio Service, Content Decryption Module Service, Network Service, Video Capture, etc.\n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Gets or sets the non-localized name of the process.\n        /// </summary>\n        public string ServiceName { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ProcessVersions.cs",
    "content": "namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// An object listing the version strings specific to Electron\n    /// </summary>\n    /// <yremarks>Project-specific: no matching Electron structure found in MCP docs (electronjs).</yremarks>\n    /// <param name=\"Chrome\">Value representing Chrome's version string</param>\n    /// <param name=\"Electron\">Value representing Electron's version string</param>\n    /// <returns></returns>\n    public record ProcessVersions(string Chrome, string Electron);\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ProgressBarMode.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Mode for BrowserWindow/BaseWindow setProgressBar on Windows.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"Windows\")]\n    public enum ProgressBarMode\n    {\n        /// <summary>\n        /// The none\n        /// </summary>\n        none,\n\n        /// <summary>\n        /// The normal\n        /// </summary>\n        normal,\n\n        /// <summary>\n        /// The indeterminate\n        /// </summary>\n        indeterminate,\n\n        /// <summary>\n        /// The error\n        /// </summary>\n        error,\n\n        /// <summary>\n        /// The paused\n        /// </summary>\n        paused\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ProgressBarOptions.cs",
    "content": "using System.Text.Json.Serialization;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Options for BrowserWindow.setProgressBar(progress, options).\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class ProgressBarOptions\n    {\n        /// <summary>\n        /// Mode for the progress bar on Windows. Can be 'none' | 'normal' | 'indeterminate' | 'error' | 'paused'.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public ProgressBarMode Mode { get; set; } = ProgressBarMode.normal;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ProgressInfo.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with electron-updater 6.7.2</remarks>\n    public class ProgressInfo\n    {\n        /// <summary>Gets or sets the progress.</summary>\n        public string Progress { get; set; }\n\n        /// <summary>\n        /// Gets or sets bytes processed per second.\n        /// </summary>\n        public long BytesPerSecond { get; set; }\n\n        /// <summary>\n        /// Gets or sets the percentage completed (0–100).\n        /// </summary>\n        public double Percent { get; set; }\n\n        /// <summary>\n        /// Gets or sets the total number of bytes to download.\n        /// </summary>\n        public long Total { get; set; }\n\n        /// <summary>\n        /// Gets or sets the number of bytes transferred so far.\n        /// </summary>\n        public long Transferred { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ProxyConfig.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Proxy configuration for app.setProxy / session.setProxy. Matches Electron's ProxyConfig structure.\n    /// </summary>\n    public class ProxyConfig\n    {\n        /// <summary>\n        /// The proxy mode. One of: 'direct' | 'auto_detect' | 'pac_script' | 'fixed_servers' | 'system'.\n        /// Defaults to 'pac_script' if 'PacScript' is specified, otherwise defaults to 'fixed_servers'.\n        /// </summary>\n        public string Mode { get; set; }\n\n        /// <summary>\n        /// The URL associated with the PAC file.\n        /// </summary>\n        public string PacScript { get; set; }\n\n        /// <summary>\n        /// Rules indicating which proxies to use.\n        /// </summary>\n        public string ProxyRules { get; set; }\n\n        /// <summary>\n        /// Rules indicating which URLs should bypass the proxy settings.\n        /// </summary>\n        public string ProxyBypassRules { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"pacScript\">The URL associated with the PAC file.</param>\n        /// <param name=\"proxyRules\">Rules indicating which proxies to use.</param>\n        /// <param name=\"proxyBypassRules\">Rules indicating which URLs should bypass the proxy settings.</param>\n        public ProxyConfig(string pacScript, string proxyRules, string proxyBypassRules)\n        {\n            PacScript = pacScript;\n            ProxyRules = proxyRules;\n            ProxyBypassRules = proxyBypassRules;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ReadBookmark.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Result of clipboard.readBookmark(): title and url.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"macOS\")]\n    [SupportedOSPlatform(\"Windows\")]\n    public class ReadBookmark\n    {\n        /// <summary>\n        /// Gets or sets the title.\n        /// </summary>\n        /// <value>\n        /// The title.\n        /// </value>\n        public string Title { get; set; }\n\n        /// <summary>\n        /// Gets or sets the URL.\n        /// </summary>\n        /// <value>\n        /// The URL.\n        /// </value>\n        public string Url { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Rectangle.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class Rectangle\n    {\n        /// <summary>\n        /// Gets or sets the x.\n        /// </summary>\n        /// <value>\n        /// The x.\n        /// </value>\n        public int X { get; set; }\n\n        /// <summary>\n        /// Gets or sets the y.\n        /// </summary>\n        /// <value>\n        /// The y.\n        /// </value>\n        public int Y { get; set; }\n\n        /// <summary>\n        /// Gets or sets the width.\n        /// </summary>\n        /// <value>\n        /// The width.\n        /// </value>\n        public int Width { get; set; }\n\n        /// <summary>\n        /// Gets or sets the height.\n        /// </summary>\n        /// <value>\n        /// The height.\n        /// </value>\n        public int Height { get; set; }\n\n        /// <summary>\n        /// Convert this <see cref=\"Rectangle\"/> to <see cref=\"System.Drawing.Rectangle\"/>.\n        /// </summary>\n        /// <param name=\"rectangle\">The rectangle.</param>\n        public static implicit operator System.Drawing.Rectangle(Rectangle rectangle)\n        {\n            return new System.Drawing.Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/RelaunchOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Options for app.relaunch: optional args array and execPath.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class RelaunchOptions\n    {\n        /// <summary>\n        /// Command-line arguments for the relaunched instance.\n        /// </summary>\n        public string[] Args { get; set; }\n\n        /// <summary>\n        /// Executable path to relaunch instead of the current app.\n        /// </summary>\n        public string ExecPath { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ReleaseNoteInfo.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with electron-updater 6.7.2</remarks>\n    public class ReleaseNoteInfo\n    {\n        /// <summary>\n        /// Gets or sets the version.\n        /// </summary>\n        public string Version { get; set; }\n\n        /// <summary>\n        /// Gets or sets the note text.\n        /// </summary>\n        public string Note { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/RemovePassword.cs",
    "content": "using System.Text.Json.Serialization;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <yremarks>Undecidable from MCP: no typed structure for session.clearAuthCache parameters.</yremarks>\n    public class RemovePassword\n    {\n        /// <summary>\n        /// When provided, the authentication info related to the origin will only be\n        /// removed otherwise the entire cache will be cleared.\n        /// </summary>\n        public string Origin { get; set; }\n\n        /// <summary>\n        /// Credentials of the authentication. Must be provided if removing by origin.\n        /// </summary>\n        public string Password { get; set; }\n\n        /// <summary>\n        /// Realm of the authentication. Must be provided if removing by origin.\n        /// </summary>\n        public string Realm { get; set; }\n\n        /// <summary>\n        /// Scheme of the authentication. Can be basic, digest, ntlm, negotiate.\n        /// Must be provided if removing by origin.\n        /// </summary>\n        public Scheme Scheme { get; set; }\n\n        /// <summary>\n        /// password.\n        /// </summary>\n        public string Type { get; set; }\n\n        /// <summary>\n        /// Credentials of the authentication. Must be provided if removing by origin.\n        /// </summary>\n        public string Username { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"type\">password.</param>\n        public RemovePassword(string type)\n        {\n            Type = type;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ResizeOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Options for NativeImage.resize: optional width/height and quality.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class ResizeOptions\n    {\n        /// <summary>\n        /// Gets or sets the width\n        /// </summary>\n        public int? Width { get; set; }\n\n        /// <summary>\n        /// Gets or sets the height\n        /// </summary>\n        public int? Height { get; set; }\n\n        /// <summary>\n        /// 'good', 'better', or 'best'. Default is 'best'.\n        /// </summary>\n        public string Quality { get; set; } = \"best\";\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/SaveDialogOptions.cs",
    "content": "﻿using ElectronNET.API.Entities;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Options for dialog.showSaveDialog / dialog.showSaveDialogSync.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class SaveDialogOptions\n    {\n        /// <summary>\n        /// Gets or sets the title.\n        /// </summary>\n        /// <value>\n        /// The title.\n        /// </value>\n        public string Title { get; set; }\n\n        /// <summary>\n        /// Absolute directory path, absolute file path, or file name to use by default.\n        /// </summary>\n        public string DefaultPath { get; set; }\n\n        /// <summary>\n        /// Gets or sets the custom label for the confirmation button; when left empty the default label will be used.\n        /// </summary>\n        public string ButtonLabel { get; set; }\n\n        /// <summary>\n        /// Properties for the save dialog. Supported values:\n        /// showHiddenFiles | createDirectory (macOS) | treatPackageAsDirectory (macOS) | showOverwriteConfirmation (Linux) | dontAddToRecent (Windows)\n        /// </summary>\n        public SaveDialogProperty[] Properties { get; set; }\n\n        /// <summary>\n        /// Gets or sets the filters specifying an array of file types that can be displayed or\n        /// selected when you want to limit the user to a specific type. For example:\n        /// </summary>\n        /// <example>\n        /// <code>\n        /// new FileFilter[]\n        /// {\n        ///  new FileFiler { Name = \"Images\", Extensions = new string[] { \"jpg\", \"png\", \"gif\" } },\n        ///  new FileFiler { Name = \"Movies\", Extensions = new string[] { \"mkv\", \"avi\", \"mp4\" } },\n        ///  new FileFiler { Name = \"Custom File Type\", Extensions= new string[] {\"as\" } },\n        ///  new FileFiler { Name = \"All Files\", Extensions= new string[] { \"*\" } }\n        /// }\n        /// </code>\n        /// </example>\n        public FileFilter[] Filters { get; set; }\n\n        /// <summary>\n        /// Gets or sets the message to display above text fields.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string Message { get; set; }\n\n        /// <summary>\n        /// Gets or sets the custom label for the text displayed in front of the filename text field.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public string NameFieldLabel { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to show the tags input box. Defaults to true.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool ShowsTagField { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to create a security scoped bookmark when packaged for the Mac App Store. If enabled and the file doesn't already exist a blank file will be created at the chosen path.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool SecurityScopedBookmarks { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/SaveDialogProperty.cs",
    "content": "using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Properties supported by dialog.showSaveDialog / showSaveDialogSync.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public enum SaveDialogProperty\n    {\n        /// <summary>\n        /// Show hidden files in dialog.\n        /// </summary>\n        showHiddenFiles,\n\n        /// <summary>\n        /// Allow creating new directories from dialog (macOS).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        createDirectory,\n\n        /// <summary>\n        /// Treat packages, such as .app folders, as a directory instead of a file (macOS).\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        treatPackageAsDirectory,\n\n        /// <summary>\n        /// Sets whether the user will be presented a confirmation dialog if the user types a file name that already exists (Linux).\n        /// </summary>\n        [SupportedOSPlatform(\"linux\")]\n        showOverwriteConfirmation,\n\n        /// <summary>\n        /// Do not add the item being saved to the recent documents list (Windows).\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        dontAddToRecent\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Scheme.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Authentication scheme names used by webContents 'login' authInfo.scheme.\n    /// </summary>\n    /// <yremarks>Undecidable from MCP: no typed enum is defined in docs; kept as project enum to reflect commonly observed values.</yremarks>\n    public enum Scheme\n    {\n        /// <summary>\n        /// \n        /// </summary>\n        basic,\n\n        /// <summary>\n        /// \n        /// </summary>\n        digest,\n\n        /// <summary>\n        /// \n        /// </summary>\n        ntlm,\n\n        /// <summary>\n        /// \n        /// </summary>\n        negotiate\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/SemVer.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <yremarks>Project-specific: no matching Electron structure found in MCP docs (electronjs).</yremarks>\n    public class SemVer\n    {\n        /// <summary>\n        /// \n        /// </summary>\n        public string Raw { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public bool Loose { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public SemVerOptions Options { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public int Major { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public int Minor { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public int Patch { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public string Version { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public string[] Build { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public string[] Prerelease { get; set; }\n    }\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <yremarks>Project-specific: no matching Electron structure found in MCP docs (electronjs).</yremarks>\n    public class SemVerOptions\n    {\n        /// <summary>\n        /// \n        /// </summary>\n        public bool? Loose { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public bool? IncludePrerelease { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/SharingItem.cs",
    "content": "using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// SharingItem for MenuItem role 'shareMenu' (macOS).\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"macos\")]\n    public class SharingItem\n    {\n        /// <summary>\n        /// An array of text to share.\n        /// </summary>\n        public string[] Texts { get; set; }\n\n        /// <summary>\n        /// An array of files to share.\n        /// </summary>\n        public string[] FilePaths { get; set; }\n\n        /// <summary>\n        /// An array of URLs to share.\n        /// </summary>\n        public string[] Urls { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ShortcutDetails.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Structure of a shortcut.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"windows\")]\n    public class ShortcutDetails\n    {\n        /// <summary>\n        /// The Application User Model ID. Default is <see cref=\"string.Empty\"/>.\n        /// </summary>\n        public string AppUserModelId { get; set; }\n\n        /// <summary>\n        /// The arguments to be applied to <see cref=\"Target\"/> when launching from this shortcut. Default is <see cref=\"string.Empty\"/>.\n        /// </summary>\n        public string Args { get; set; }\n\n        /// <summary>\n        /// The working directory. Default is <see cref=\"string.Empty\"/>.\n        /// </summary>\n        public string Cwd { get; set; }\n\n        /// <summary>\n        /// The description of the shortcut. Default is <see cref=\"string.Empty\"/>.\n        /// </summary>\n        public string Description { get; set; }\n\n        /// <summary>\n        /// The path to the icon, can be a DLL or EXE. <see cref=\"Icon\"/> and <see cref=\"IconIndex\"/> have to be set\n        /// together. Default is <see cref=\"string.Empty\"/>, which uses the target's icon.\n        /// </summary>\n        public string Icon { get; set; }\n\n        /// <summary>\n        /// The resource ID of icon when <see cref=\"Icon\"/> is a DLL or EXE. Default is 0.\n        /// </summary>\n        public int IconIndex { get; set; }\n\n        /// <summary>\n        /// The Application Toast Activator CLSID. Needed for participating in Action Center.\n        /// </summary>\n        [SupportedOSPlatform(\"windows\")]\n        public string ToastActivatorClsid { get; set; }\n\n        /// <summary>\n        /// The target to launch from this shortcut.\n        /// </summary>\n        public string Target { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ShortcutLinkOperation.cs",
    "content": "﻿using System.ComponentModel;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Defines the ShortcutLinkOperation enumeration.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"Windows\")]\n    public enum ShortcutLinkOperation\n    {\n        /// <summary>\n        /// Creates a new shortcut, overwriting if necessary.\n        /// </summary>\n        Create,\n\n        /// <summary>\n        /// Updates specified properties only on an existing shortcut.\n        /// </summary>\n        Update,\n\n        /// <summary>\n        /// Overwrites an existing shortcut, fails if the shortcut doesn't exist.\n        /// </summary>\n        Replace\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Size.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class Size\n    {\n        /// <summary>\n        /// Gets or sets the width.\n        /// </summary>\n        /// <value>\n        /// The width.\n        /// </value>\n        public int Width { get; set; }\n\n        /// <summary>\n        /// Gets or sets the height.\n        /// </summary>\n        /// <value>\n        /// The height.\n        /// </value>\n        public int Height { get; set; }\n\n        /// <summary>\n        /// Convert this <see cref=\"Size\"/> to <see cref=\"System.Drawing.Size\"/>.\n        /// </summary>\n        /// <param name=\"size\">The size.</param>\n        public static implicit operator System.Drawing.Size(Size size)\n        {\n            return new System.Drawing.Size(size.Width, size.Height);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ThemeSourceMode.cs",
    "content": "﻿using System.ComponentModel;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Defines the ThemeSourceMode enumeration.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public enum ThemeSourceMode\n    {\n        /// <summary>\n        /// Operating system default.\n        /// </summary>\n        System,\n\n        /// <summary>\n        /// Light theme.\n        /// </summary>\n        Light,\n\n        /// <summary>\n        /// Dark theme.\n        /// </summary>\n        Dark\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ThumbarButton.cs",
    "content": "using System;\nusing System.Text.Json.Serialization;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Thumbnail toolbar button for Windows taskbar.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"windows\")]\n    public class ThumbarButton\n    {\n        /// <summary>\n        /// Gets the identifier.\n        /// </summary>\n        /// <value>\n        /// The identifier.\n        /// </value>\n        public string Id { get; internal set; }\n\n        /// <summary>\n        /// Gets or sets the click.\n        /// </summary>\n        /// <value>\n        /// The click.\n        /// </value>\n        [JsonIgnore]\n        public Action Click { get; set; }\n\n        /// <summary>\n        /// Control specific states and behaviors of the button. By default, it is [\"enabled\"].\n        /// \n        /// enabled - The button is active and available to the user.\n        /// disabled - The button is disabled.It is present, but has a visual state indicating it will not respond to user action.\n        /// dismissonclick - When the button is clicked, the thumbnail window closes immediately.\n        /// nobackground - Do not draw a button border, use only the image.\n        /// hidden - The button is not shown to the user.\n        /// noninteractive - The button is enabled but not interactive; no pressed button state is drawn.This value is intended for instances where the button is used in a notification.\n        /// </summary>\n        public ThumbarButtonFlag[] Flags { get; set; }\n\n        /// <summary>\n        /// The icon showing in thumbnail toolbar.\n        /// </summary>\n        public string Icon { get; set; }\n\n        /// <summary>\n        /// The text of the button's tooltip.\n        /// </summary>\n        public string Tooltip { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ThumbarButton\"/> class.\n        /// </summary>\n        /// <param name=\"icon\">The icon.</param>\n        public ThumbarButton(string icon)\n        {\n            Icon = icon;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ThumbarButtonFlag.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Flags for Windows taskbar thumbnail toolbar buttons.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"windows\")]\n    public enum ThumbarButtonFlag\n    {\n        /// <summary>\n        /// The button is active and available to the user.\n        /// </summary>\n        enabled,\n\n        /// <summary>\n        /// The button is disabled.It is present, but has a visual state indicating it will not respond to user action.\n        /// </summary>\n        disabled,\n\n        /// <summary>\n        /// When the button is clicked, the thumbnail window closes immediately.\n        /// </summary>\n        dismissonclick,\n\n        /// <summary>\n        /// Do not draw a button border, use only the image.\n        /// </summary>\n        nobackground,\n\n        /// <summary>\n        /// The button is not shown to the user.\n        /// </summary>\n        hidden,\n\n        /// <summary>\n        /// The button is enabled but not interactive; no pressed button state is drawn.This value is intended for instances where the button is used in a notification.\n        /// </summary>\n        noninteractive\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/TitleBarOverlay.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities;\n\n/// <summary>\n/// Configures the window's title bar overlay when using a frameless window.\n/// </summary>\n/// <remarks>Up-to-date with Electron API 39.2</remarks>\npublic class TitleBarOverlay\n{\n    private readonly bool? _value;\n\n    public TitleBarOverlay()\n    {\n    }\n\n    private TitleBarOverlay(bool value) : this() => _value = value;\n\n    /// <summary>\n    /// Gets or sets the CSS color of the Window Controls Overlay when enabled.\n    /// OS-specific per MCP: available on Windows and Linux.\n    /// </summary>\n    [SupportedOSPlatform(\"windows\")]\n    [SupportedOSPlatform(\"linux\")]\n    public string Color { get; set; }\n\n    /// <summary>\n    /// Gets or sets the height of the title bar and Window Controls Overlay in pixels. Default is system height.\n    /// </summary>\n    public int Height { get; set; }\n\n    /// <summary>\n    /// Gets or sets the CSS color of the symbols on the Window Controls Overlay when enabled.\n    /// OS-specific per MCP: available on Windows and Linux.\n    /// </summary>\n    [SupportedOSPlatform(\"windows\")]\n    [SupportedOSPlatform(\"linux\")]\n    public string SymbolColor { get; set; }\n\n    /// <summary>\n    /// Allows using a bare boolean for titleBarOverlay in options (true/false).\n    /// </summary>\n    public static implicit operator bool?(TitleBarOverlay titleBarOverlay) => titleBarOverlay?._value;\n\n    /// <summary>\n    /// Allows constructing from a bare boolean (true/false) for titleBarOverlay.\n    /// </summary>\n    public static implicit operator TitleBarOverlay(bool value) => new(value);\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/TitleBarStyle.cs",
    "content": "using System.Text.Json.Serialization;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public enum TitleBarStyle\n    {\n        /// <summary>\n        /// The default style\n        /// </summary>\n        [JsonPropertyName(\"default\")]\n        defaultStyle,\n\n        /// <summary>\n        /// The hidden\n        /// </summary>\n        hidden,\n\n        /// <summary>\n        /// The hidden inset\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        hiddenInset,\n\n        /// <summary>\n        /// The custom buttons on hover\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        customButtonsOnHover\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ToBitmapOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Options for nativeImage.toBitmap; supports optional scaleFactor (defaults to 1.0) per MCP.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class ToBitmapOptions\n    {\n        /// <summary>\n        /// Gets or sets the image scale factor. Defaults to 1.0.\n        /// </summary>\n        public float ScaleFactor { get; set; } = 1.0f;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ToDataUrlOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class ToDataUrlOptions\n    {\n        /// <summary>\n        /// Gets or sets the image scale factor. Defaults to 1.0.\n        /// </summary>\n        public float ScaleFactor { get; set; } = 1.0f;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/ToPNGOptions.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class ToPNGOptions\n    {\n        /// <summary>\n        /// Gets or sets the image scale factor. Defaults to 1.0.\n        /// </summary>\n        public float ScaleFactor { get; set; } = 1.0f;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/TrayClickEventArgs.cs",
    "content": "﻿using ElectronNET.API.Entities;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public class TrayClickEventArgs\n    {\n        /// <summary>\n        /// Gets or sets a value indicating whether [alt key].\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [alt key]; otherwise, <c>false</c>.\n        /// </value>\n        public bool AltKey { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether [shift key].\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [shift key]; otherwise, <c>false</c>.\n        /// </value>\n        public bool ShiftKey { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether [control key].\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [control key]; otherwise, <c>false</c>.\n        /// </value>\n        public bool CtrlKey { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether [meta key].\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [meta key]; otherwise, <c>false</c>.\n        /// </value>\n        public bool MetaKey { get; set; }\n\n        /// <summary>\n        /// The bounds of tray icon.\n        /// </summary>\n        public Rectangle Bounds { get; set; }\n\n        /// <summary>\n        /// The position of the event.\n        /// </summary>\n        public Point Position { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/UpdateCancellationToken.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with electron-updater 6.7.2</remarks>\n    public class UpdateCancellationToken\n    {\n        /// <summary>\n        /// Gets or sets a value indicating whether cancellation has been requested.\n        /// </summary>\n        public bool Cancelled { get; set; }\n\n        /// <summary>\n        /// Requests cancellation of the update process.\n        /// </summary>\n        public void Cancel()\n        {\n        }\n\n        /// <summary>\n        /// Disposes the underlying cancellation token (if applicable).\n        /// </summary>\n        public void Dispose()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/UpdateCheckResult.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with electron-updater 6.7.2</remarks>\n    public class UpdateCheckResult\n    {\n        /// <summary>\n        /// Gets or sets the update information discovered by the check.\n        /// </summary>\n        public UpdateInfo UpdateInfo { get; set; } = new UpdateInfo();\n\n        /// <summary>\n        /// Gets or sets the download artifacts (if provided by the updater).\n        /// </summary>\n        public string[] Download { get; set; }\n\n        /// <summary>\n        /// Gets or sets the cancellation token for the update process.\n        /// </summary>\n        public UpdateCancellationToken CancellationToken { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/UpdateFileInfo.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with electron-updater 6.7.2</remarks>\n    public class UpdateFileInfo : BlockMapDataHolder\n    {\n        /// <summary>\n        /// Gets or sets the URL of the update file.\n        /// </summary>\n        public string Url { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/UpdateInfo.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with electron-updater 6.7.2</remarks>\n    public class UpdateInfo\n    {\n        /// <summary>\n        /// Gets or sets the version.\n        /// </summary>\n        public string Version { get; set; }\n\n        /// <summary>\n        /// Gets or sets the files included in this update.\n        /// </summary>\n        public UpdateFileInfo[] Files { get; set; } = new UpdateFileInfo[0];\n\n        /// <summary>\n        /// Gets or sets the release name.\n        /// </summary>\n        public string ReleaseName { get; set; }\n\n        /// <summary>\n        /// Gets or sets the release notes.\n        /// </summary>\n        public ReleaseNoteInfo[] ReleaseNotes { get; set; } = new ReleaseNoteInfo[0];\n\n        /// <summary>\n        /// Gets or sets the release date.\n        /// </summary>\n        public string ReleaseDate { get; set; }\n\n        /// <summary>\n        /// Gets or sets the staged rollout percentage, 0-100.\n        /// </summary>\n        public double StagingPercentage { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/UploadFile.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class UploadFile : IPostData\n    {\n        /// <summary>\n        /// Gets the type discriminator; constant 'file'.\n        /// </summary>\n        public string Type { get; } = \"file\";\n\n        /// <summary>\n        /// Gets or sets the path of the file to be uploaded.\n        /// </summary>\n        public string FilePath { get; set; }\n\n        /// <summary>\n        /// Gets or sets the offset from the beginning of the file being uploaded, in bytes. Defaults to 0.\n        /// </summary>\n        public long Offset { get; set; } = 0;\n\n        /// <summary>\n        /// Gets or sets the number of bytes to read from offset. Defaults to 0.\n        /// </summary>\n        public long Length { get; set; } = 0;\n\n        /// <summary>\n        /// Gets or sets the last modification time in number of seconds since the UNIX epoch. Defaults to 0.\n        /// </summary>\n        public double ModificationTime { get; set; } = 0;\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/UploadRawData.cs",
    "content": "﻿namespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class UploadRawData : IPostData\n    {\n        /// <summary>\n        /// Gets the type discriminator; constant 'rawData'.\n        /// </summary>\n        public string Type { get; } = \"rawData\";\n\n        /// <summary>\n        /// Gets or sets the data to be uploaded as raw bytes (Electron Buffer).\n        /// </summary>\n        public byte[] Bytes { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/UserTask.cs",
    "content": "﻿using System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Windows Task item used by app.setUserTasks.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"Windows\")]\n    public class UserTask\n    {\n        /// <summary>\n        /// Gets or sets the arguments.\n        /// </summary>\n        /// <value>\n        /// The arguments.\n        /// </value>\n        public string Arguments { get; set; }\n\n        /// <summary>\n        /// Gets or sets the description.\n        /// </summary>\n        /// <value>\n        /// The description.\n        /// </value>\n        public string Description { get; set; }\n\n        /// <summary>\n        /// Gets or sets the index of the icon.\n        /// </summary>\n        /// <value>\n        /// The index of the icon.\n        /// </value>\n        public int IconIndex { get; set; }\n\n        /// <summary>\n        /// Gets or sets the icon path.\n        /// </summary>\n        /// <value>\n        /// The icon path.\n        /// </value>\n        public string IconPath { get; set; }\n\n        /// <summary>\n        /// Gets or sets the program.\n        /// </summary>\n        /// <value>\n        /// The program.\n        /// </value>\n        public string Program { get; set; }\n\n        /// <summary>\n        /// Gets or sets the title.\n        /// </summary>\n        /// <value>\n        /// The title.\n        /// </value>\n        public string Title { get; set; }\n\n        /// <summary>\n        /// The working directory. Default is <see cref=\"string.Empty\"/>.\n        /// </summary>\n        public string WorkingDirectory { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/Vibrancy.cs",
    "content": "﻿using System.Runtime.Serialization;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// Vibrancy types for BrowserWindow on macOS.\n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    [SupportedOSPlatform(\"macos\")]\n    public enum Vibrancy\n    {\n        /// <summary>\n        /// Appearance-based vibrancy.\n        /// </summary>\n        [EnumMember(Value = \"appearance-based\")]\n        appearanceBased,\n\n        /// <summary>\n        /// Title bar area.\n        /// </summary>\n        titlebar,\n\n        /// <summary>\n        /// Selection highlight.\n        /// </summary>\n        selection,\n\n        /// <summary>\n        /// Menu background.\n        /// </summary>\n        menu,\n\n        /// <summary>\n        /// Popover background.\n        /// </summary>\n        popover,\n\n        /// <summary>\n        /// Sidebar background.\n        /// </summary>\n        sidebar,\n\n        /// <summary>\n        /// Header background.\n        /// </summary>\n        header,\n\n        /// <summary>\n        /// Sheet background.\n        /// </summary>\n        sheet,\n\n        /// <summary>\n        /// Window background.\n        /// </summary>\n        window,\n\n        /// <summary>\n        /// Heads-up display.\n        /// </summary>\n        hud,\n\n        /// <summary>\n        /// Fullscreen UI background.\n        /// </summary>\n        [EnumMember(Value = \"fullscreen-ui\")]\n        fullscreenUi,\n\n        /// <summary>\n        /// Tooltip background.\n        /// </summary>\n        tooltip,\n\n        /// <summary>\n        /// Content background.\n        /// </summary>\n        content,\n\n        /// <summary>\n        /// Under-window background.\n        /// </summary>\n        [EnumMember(Value = \"under-window\")]\n        underWindow,\n\n        /// <summary>\n        /// Under-page background.\n        /// </summary>\n        [EnumMember(Value = \"under-page\")]\n        underPage\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Entities/WebPreferences.cs",
    "content": "using System.ComponentModel;\nusing System.Runtime.Versioning;\n\nnamespace ElectronNET.API.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>Up-to-date with Electron API 39.2</remarks>\n    public class WebPreferences\n    {\n        /// <summary>\n        /// Whether to enable DevTools. If it is set to false, can not use\n        /// BrowserWindow.webContents.openDevTools() to open DevTools.Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool DevTools { get; set; } = true;\n\n        /// <summary>\n        /// Whether node integration is enabled. Required to enable IPC. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool NodeIntegration { get; set; } = true;\n\n        /// <summary>\n        /// Whether node integration is enabled in web workers. Default is false.\n        /// </summary>\n        public bool NodeIntegrationInWorker { get; set; }\n\n        /// <summary>\n        /// Experimental option for enabling Node.js support in sub-frames such as iframes and child windows.\n        /// </summary>\n        public bool NodeIntegrationInSubFrames { get; set; }\n\n        /// <summary>\n        /// Specifies a script that will be loaded before other scripts run in the page.\n        /// This script will always have access to node APIs no matter whether node\n        /// integration is turned on or off.The value should be the absolute file path to\n        /// the script. When node integration is turned off, the preload script can\n        /// reintroduce Node global symbols back to the global scope.\n        /// </summary>\n        public string Preload { get; set; }\n\n        /// <summary>\n        /// If set, this will sandbox the renderer associated with the window, making it compatible with the Chromium OS-level sandbox and disabling the Node.js engine. This is not the same as the nodeIntegration option and the APIs available to the preload script are more limited. Default is true since Electron 20. The sandbox will automatically be disabled when nodeIntegration is set to true.\n        /// </summary>\n        public bool Sandbox { get; set; }\n\n        /// <summary>\n        /// Sets the session used by the page according to the session's partition string.\n        /// If partition starts with persist:, the page will use a persistent session\n        /// available to all pages in the app with the same partition.If there is no\n        /// persist: prefix, the page will use an in-memory session. By assigning the same\n        /// partition, multiple pages can share the same session.Default is the default\n        /// session.\n        /// </summary>\n        public string Partition { get; set; }\n\n        /// <summary>\n        /// The default zoom factor of the page, 3.0 represents 300%. Default is 1.0.\n        /// </summary>\n        [DefaultValue(1.0)]\n        public double ZoomFactor { get; set; } = 1.0;\n\n        /// <summary>\n        /// Enables JavaScript support. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Javascript { get; set; } = true;\n\n        /// <summary>\n        /// When false, it will disable the same-origin policy (usually using testing\n        /// websites by people), and set allowRunningInsecureContent to true if this options\n        /// has not been set by user. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool WebSecurity { get; set; } = true;\n\n        /// <summary>\n        /// Allow an https page to run JavaScript, CSS or plugins from http URLs. Default is\n        /// false.\n        /// </summary>\n        public bool AllowRunningInsecureContent { get; set; }\n\n        /// <summary>\n        /// Enables image support. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Images { get; set; } = true;\n\n        /// <summary>\n        /// Specifies how to run image animations (e.g. GIFs). Can be 'animate', 'animateOnce' or 'noAnimation'. Default is 'animate'.\n        /// </summary>\n        public string ImageAnimationPolicy { get; set; }\n\n        /// <summary>\n        /// Make TextArea elements resizable. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool TextAreasAreResizable { get; set; } = true;\n\n        /// <summary>\n        /// Enables WebGL support. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Webgl { get; set; } = true;\n\n        /// <summary>\n        /// Enables WebAudio support. Default is true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Webaudio { get; set; } = true;\n\n        /// <summary>\n        /// Whether plugins should be enabled. Default is false.\n        /// </summary>\n        public bool Plugins { get; set; }\n\n        /// <summary>\n        /// Enables Chromium's experimental features. Default is false.\n        /// </summary>\n        public bool ExperimentalFeatures { get; set; }\n\n        /// <summary>\n        /// Enables Chromium's experimental canvas features. Default is false.\n        /// </summary>\n        /// <remarks>Not documented by MCP electronjs web-preferences.</remarks>\n        public bool ExperimentalCanvasFeatures { get; set; }\n\n        /// <summary>\n        /// Enables scroll bounce (rubber banding) effect on macOS. Default is false.\n        /// </summary>\n        [SupportedOSPlatform(\"macos\")]\n        public bool ScrollBounce { get; set; }\n\n        /// <summary>\n        /// A list of feature strings separated by ,, like CSSVariables,KeyboardEventKey to\n        /// enable.The full list of supported feature strings can be found in the file.\n        /// </summary>\n        public string EnableBlinkFeatures { get; set; }\n\n        /// <summary>\n        /// A list of feature strings separated by ,, like CSSVariables,KeyboardEventKey to\n        /// disable.The full list of supported feature strings can be found in the file.\n        /// </summary>\n        public string DisableBlinkFeatures { get; set; }\n\n        /// <summary>\n        /// Sets the default font for the font-family.\n        /// </summary>\n        public DefaultFontFamily DefaultFontFamily { get; set; }\n\n        /// <summary>\n        /// Defaults to 16.\n        /// </summary>\n        public int DefaultFontSize { get; set; } = 16;\n\n        /// <summary>\n        /// Defaults to 13.\n        /// </summary>\n        [DefaultValue(13)]\n        public int DefaultMonospaceFontSize { get; set; } = 13;\n\n        /// <summary>\n        /// Defaults to 0.\n        /// </summary>\n        [DefaultValue(0)]\n        public int MinimumFontSize { get; set; } = 0;\n\n        /// <summary>\n        /// Defaults to ISO-8859-1.\n        /// </summary>\n        /// <remarks>Not documented by MCP electronjs web-preferences.</remarks>\n        public string DefaultEncoding { get; set; }\n\n        /// <summary>\n        /// Whether to throttle animations and timers when the page becomes background. This\n        /// also affects the[Page Visibility API][#page-visibility]. Defaults to true.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool BackgroundThrottling { get; set; } = true;\n\n        /// <summary>\n        /// Whether to enable offscreen rendering for the browser window. Defaults to false.\n        /// </summary>\n        public bool Offscreen { get; set; }\n\n        /// <summary>\n        /// Whether to run Electron APIs and the specified preload script in a separate\n        /// JavaScript context. Defaults to false. The context that the preload script runs\n        /// in will still have full access to the document and window globals but it will\n        /// use its own set of JavaScript builtins (Array, Object, JSON, etc.) and will be\n        /// isolated from any changes made to the global environment by the loaded page.The\n        /// Electron API will only be available in the preload script and not the loaded\n        /// page. This option should be used when loading potentially untrusted remote\n        /// content to ensure the loaded content cannot tamper with the preload script and\n        /// any Electron APIs being used. This option uses the same technique used by . You\n        /// can access this context in the dev tools by selecting the 'Electron Isolated\n        /// Context' entry in the combo box at the top of the Console tab. This option is\n        /// currently experimental and may change or be removed in future Electron releases.\n        /// </summary>\n        [DefaultValue(false)]\n        public bool ContextIsolation { get; set; } = false;\n\n        /// <summary>\n        /// Whether to use native window.open(). Defaults to false. This option is currently experimental.\n        /// </summary>\n        public bool NativeWindowOpen { get; set; }\n\n        /// <summary>\n        /// Whether to enable the Webview. Defaults to the value of the nodeIntegration option. The\n        /// preload script configured for the Webview will have node integration enabled\n        /// when it is executed so you should ensure remote/untrusted content is not able to\n        /// create a Webview tag with a possibly malicious preload script.You can use the\n        /// will-attach-webview event on to strip away the preload script and to validate or\n        /// alter the Webview's initial settings.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [webview tag]; otherwise, <c>false</c>.\n        /// </value>\n        [DefaultValue(false)]\n        public bool WebviewTag { get; set; } = false;\n\n        /// <summary>\n        /// Whether to enable the remote module. Defaults to false.\n        /// </summary>\n        [DefaultValue(false)]\n        public bool EnableRemoteModule { get; set; } = false;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to enable preferred size mode. The preferred size is the minimum size needed to contain the layout of the document—without requiring scrolling. Enabling this will cause the 'preferred-size-changed' event to be emitted on the WebContents when the preferred size changes. Default is false.\n        /// </summary>\n        [DefaultValue(false)]\n        public bool EnablePreferredSizeMode { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to enable background transparency for the guest page. Default is true.\n        /// Note: The guest page's text and background colors are derived from the color scheme of its root element. When transparency is enabled, the text color will still change accordingly but the background will remain transparent.\n        /// </summary>\n        [DefaultValue(true)]\n        public bool Transparent { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to enable the 'paste' execCommand. Deprecated. Default is false.\n        /// </summary>\n        [DefaultValue(false)]\n        [System.Obsolete(\"enableDeprecatedPaste is deprecated in Electron; avoid using.\")]\n        public bool EnableDeprecatedPaste { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Extensions/MenuItemExtensions.cs",
    "content": "﻿using ElectronNET.API.Entities;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace ElectronNET.API.Extensions\n{\n    internal static class MenuItemExtensions\n    {\n        public static MenuItem[] AddMenuItemsId(this MenuItem[] menuItems)\n        {\n            for (int index = 0; index < menuItems.Length; index++)\n            {\n                var menuItem = menuItems[index];\n                if (menuItem?.Submenu?.Length > 0)\n                {\n                    AddMenuItemsId(menuItem.Submenu);\n                }\n\n                if (string.IsNullOrEmpty(menuItem.Id) && menuItem.Click != null)\n                {\n                    menuItem.Id = Guid.NewGuid().ToString();\n                }\n            }\n\n            return menuItems;\n        }\n\n        public static MenuItem GetMenuItem(this List<MenuItem> menuItems, string id)\n        {\n            MenuItem result = new MenuItem();\n\n            foreach (var item in menuItems)\n            {\n                if (item.Id == id)\n                {\n                    result = item;\n                }\n                else if (item?.Submenu?.Length > 0)\n                {\n                    var menuItem = GetMenuItem(item.Submenu.ToList(), id);\n                    if (menuItem.Id == id)\n                    {\n                        result = menuItem;\n                    }\n                }\n            }\n\n            return result;\n        }\n\n        public static MenuItem[] AddSubmenuTypes(this MenuItem[] menuItems)\n        {\n            for (int index = 0; index < menuItems.Length; index++)\n            {\n                var menuItem = menuItems[index];\n                if (menuItem?.Submenu?.Length > 0)\n                {\n                    if (menuItem.Type == MenuType.normal)\n                    {\n                        menuItem.Type = MenuType.submenu;\n                    }\n\n                    AddSubmenuTypes(menuItem.Submenu);\n                }\n            }\n\n            return menuItems;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Extensions/ThumbarButtonExtensions.cs",
    "content": "﻿using ElectronNET.API.Entities;\nusing System;\nusing System.Collections.Generic;\n\nnamespace ElectronNET.API.Extensions\n{\n    internal static class ThumbarButtonExtensions\n    {\n        public static ThumbarButton[] AddThumbarButtonsId(this ThumbarButton[] thumbarButtons)\n        {\n            for (int index = 0; index < thumbarButtons.Length; index++)\n            {\n                var thumbarButton = thumbarButtons[index];\n\n                if (string.IsNullOrEmpty(thumbarButton.Id))\n                {\n                    thumbarButton.Id = Guid.NewGuid().ToString();\n                }\n            }\n\n            return thumbarButtons;\n        }\n\n        public static ThumbarButton GetThumbarButton(this List<ThumbarButton> thumbarButtons, string id)\n        {\n            ThumbarButton result = new ThumbarButton(\"\");\n\n            foreach (var item in thumbarButtons)\n            {\n                if (item.Id == id)\n                {\n                    result = item;\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/GlobalShortcut.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Detect keyboard events when the application does not have keyboard focus.\n    /// </summary>\n    public sealed class GlobalShortcut\n    {\n        private static GlobalShortcut _globalShortcut;\n        private static object _syncRoot = new object();\n\n        internal GlobalShortcut()\n        {\n        }\n\n        internal static GlobalShortcut Instance\n        {\n            get\n            {\n                if (_globalShortcut == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_globalShortcut == null)\n                        {\n                            _globalShortcut = new GlobalShortcut();\n                        }\n                    }\n                }\n\n                return _globalShortcut;\n            }\n        }\n\n        private Dictionary<string, Action> _shortcuts = new Dictionary<string, Action>();\n\n        /// <summary>\n        /// Registers a global shortcut of accelerator.\n        /// The callback is called when the registered shortcut is pressed by the user.\n        /// \n        /// When the accelerator is already taken by other applications, this call will\n        /// silently fail.This behavior is intended by operating systems, since they don’t\n        /// want applications to fight for global shortcuts.\n        /// </summary>\n        public void Register(string accelerator, Action function)\n        {\n            if (!_shortcuts.ContainsKey(accelerator))\n            {\n                _shortcuts.Add(accelerator, function);\n\n                BridgeConnector.Socket.Off(\"globalShortcut-pressed\");\n                BridgeConnector.Socket.On<string>(\"globalShortcut-pressed\", (shortcut) =>\n                {\n                    if (_shortcuts.TryGetValue(shortcut, out var action))\n                    {\n                        action();\n                    }\n                });\n\n                BridgeConnector.Socket.Emit(\"globalShortcut-register\", accelerator);\n            }\n        }\n\n        /// <summary>\n        /// When the accelerator is already taken by other applications,\n        /// this call will still return false. This behavior is intended by operating systems,\n        /// since they don’t want applications to fight for global shortcuts.\n        /// </summary>\n        /// <returns>Whether this application has registered accelerator.</returns>\n        public Task<bool> IsRegisteredAsync(string accelerator)\n        {\n            var tcs = new TaskCompletionSource<bool>();\n\n            BridgeConnector.Socket.Once<bool>(\"globalShortcut-isRegisteredCompleted\", tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"globalShortcut-isRegistered\", accelerator);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Unregisters the global shortcut of accelerator.\n        /// </summary>\n        public void Unregister(string accelerator)\n        {\n            _shortcuts.Remove(accelerator);\n            BridgeConnector.Socket.Emit(\"globalShortcut-unregister\", accelerator);\n        }\n\n        /// <summary>\n        /// Unregisters all of the global shortcuts.\n        /// </summary>\n        public void UnregisterAll()\n        {\n            _shortcuts.Clear();\n            BridgeConnector.Socket.Emit(\"globalShortcut-unregisterAll\");\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/HostHook.cs",
    "content": "using ElectronNET.API.Serialization;\nusing System;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Allows you to execute native JavaScript/TypeScript code from the host process.\n    /// \n    /// It is only possible if the Electron.NET CLI has previously added an\n    /// ElectronHostHook directory:\n    /// <c>electronize add HostHook</c>\n    /// </summary>\n    public sealed class HostHook\n    {\n        private static HostHook _electronHostHook;\n        private static object _syncRoot = new object();\n        private string oneCallguid = Guid.NewGuid().ToString();\n\n        internal HostHook()\n        {\n        }\n\n        internal static HostHook Instance\n        {\n            get\n            {\n                if (_electronHostHook == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_electronHostHook == null)\n                        {\n                            _electronHostHook = new HostHook();\n                        }\n                    }\n                }\n\n                return _electronHostHook;\n            }\n        }\n\n        /// <summary>\n        /// Execute native JavaScript/TypeScript code.\n        /// </summary>\n        /// <param name=\"socketEventName\">Socket name registered on the host.</param>\n        /// <param name=\"arguments\">Optional parameters.</param>\n        public void Call(string socketEventName, params dynamic[] arguments)\n        {\n            BridgeConnector.Socket.Once<string>(socketEventName + \"Error\" + oneCallguid, (result) => { Electron.Dialog.ShowErrorBox(\"Host Hook Exception\", result); });\n\n            BridgeConnector.Socket.Emit(socketEventName, arguments, oneCallguid);\n        }\n\n        /// <summary>\n        /// Execute native JavaScript/TypeScript code.\n        /// </summary>\n        /// <typeparam name=\"T\">Results from the executed host code.</typeparam>\n        /// <param name=\"socketEventName\">Socket name registered on the host.</param>\n        /// <param name=\"arguments\">Optional parameters.</param>\n        /// <returns></returns>\n        public Task<T> CallAsync<T>(string socketEventName, params dynamic[] arguments)\n        {\n            var tcs = new TaskCompletionSource<T>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<string>(socketEventName + \"Error\" + guid, (result) =>\n            {\n                Electron.Dialog.ShowErrorBox(\"Host Hook Exception\", result);\n                tcs.SetException(new Exception($\"Host Hook Exception {result}\"));\n            });\n\n            BridgeConnector.Socket.Once<JsonElement>(socketEventName + \"Complete\" + guid, (result) =>\n            {\n                BridgeConnector.Socket.Off(socketEventName + \"Error\" + guid);\n                T data = default;\n\n                try\n                {\n                    data = result.Deserialize<T>(ElectronJson.Options);\n                }\n                catch (Exception exception)\n                {\n                    tcs.SetException(exception);\n                }\n\n                tcs.SetResult(data);\n            });\n\n            BridgeConnector.Socket.Emit(socketEventName, arguments, guid);\n\n            return tcs.Task;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/HybridSupport.cs",
    "content": "﻿namespace ElectronNET.API\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public static class HybridSupport\n    {\n        /// <summary>\n        /// Gets a value indicating whether this instance is electron active.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if this instance is electron active; otherwise, <c>false</c>.\n        /// </value>\n        public static bool IsElectronActive\n        {\n            get\n            {\n                return ElectronNetRuntime.RuntimeController != null;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/IpcMain.cs",
    "content": "namespace ElectronNET.API\n{\n    using System;\n    using System.Diagnostics;\n    using System.Linq;\n    using System.Text.Json;\n    using System.Text.Json.Serialization;\n    using System.Threading.Tasks;\n    using ElectronNET.Serialization;\n\n    /// <summary>\n    /// Communicate asynchronously from the main process to renderer processes.\n    /// </summary>\n    public sealed class IpcMain\n    {\n        private static IpcMain _ipcMain;\n        private static object _syncRoot = new object();\n        private static readonly JsonSerializerOptions BoxedObjectSerializationOptions = new JsonSerializerOptions\n        {\n            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,\n            WriteIndented = false,\n            Converters =\n            {\n                new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),\n                new JsonToBoxedPrimitivesConverter(),\n            }\n        };\n\n\n        internal IpcMain()\n        {\n        }\n\n        internal static IpcMain Instance\n        {\n            get\n            {\n                if (_ipcMain == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_ipcMain == null)\n                        {\n                            _ipcMain = new IpcMain();\n                        }\n                    }\n                }\n\n                return _ipcMain;\n            }\n        }\n\n        /// <summary>\n        ///  Listens to channel, when a new message arrives listener would be called with\n        ///  listener(event, args...).\n        /// </summary>\n        /// <param name=\"channel\">Channelname.</param>\n        /// <param name=\"listener\">Callback Method.</param>\n        public async Task On(string channel, Action<object> listener)\n        {\n            await BridgeConnector.Socket.Emit(\"registerIpcMainChannel\", channel).ConfigureAwait(false);\n            BridgeConnector.Socket.Off(channel);\n            BridgeConnector.Socket.On<JsonElement>(channel, (args) =>\n            {\n                var arg = FormatArguments(args);\n                listener(arg);\n            });\n        }\n\n        private static object FormatArguments(JsonElement args)\n        {\n            var objectArray = args.Deserialize<object[]>(BoxedObjectSerializationOptions).ToList();\n\n            Debug.Assert(objectArray.Count <= 2);\n\n            if (objectArray.Count == 2)\n            {\n                return objectArray[1];\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Send a message to the renderer process synchronously via channel,\n        /// you can also send arbitrary arguments.\n        /// \n        /// Note: Sending a synchronous message will block the whole renderer process,\n        /// unless you know what you are doing you should never use it.\n        /// </summary>\n        /// <param name=\"channel\"></param>\n        /// <param name=\"listener\"></param>\n        public void OnSync(string channel, Func<object, object> listener)\n        {\n            BridgeConnector.Socket.Emit(\"registerSyncIpcMainChannel\", channel);\n            BridgeConnector.Socket.On<JsonElement>(channel, (args) =>\n            {\n                var arg = FormatArguments(args);\n                var result = listener(arg);\n                BridgeConnector.Socket.Emit(channel + \"Sync\", result);\n            });\n        }\n\n        /// <summary>\n        /// Send a message to the renderer process synchronously via channel,\n        /// you can also send arbitrary arguments.\n        /// \n        /// Note: Sending a synchronous message will block the whole renderer process,\n        /// unless you know what you are doing you should never use it.\n        /// </summary>\n        /// <param name=\"channel\"></param>\n        /// <param name=\"listener\"></param>\n        public void OnSync(string channel, Func<object, Task<object>> listener)\n        {\n            BridgeConnector.Socket.Emit(\"registerSyncIpcMainChannel\", channel);\n            BridgeConnector.Socket.On<JsonElement>(channel, (args) =>\n            {\n                Task.Run(async () =>\n                {\n                    var arg = FormatArguments(args);\n                    var result = await listener(arg);\n                    BridgeConnector.Socket.Emit(channel + \"Sync\", result);\n                });\n            });\n        }\n\n        /// <summary>\n        /// Adds a one time listener method for the event. This listener is invoked only\n        ///  the next time a message is sent to channel, after which it is removed.\n        /// </summary>\n        /// <param name=\"channel\">Channelname.</param>\n        /// <param name=\"listener\">Callback Method.</param>\n        public void Once(string channel, Action<object> listener)\n        {\n            BridgeConnector.Socket.Emit(\"registerOnceIpcMainChannel\", channel);\n            BridgeConnector.Socket.Once<JsonElement>(channel, (args) =>\n            {\n                var arg = FormatArguments(args);\n                listener(arg);\n            });\n        }\n\n        /// <summary>\n        /// Removes listeners of the specified channel.\n        /// </summary>\n        /// <param name=\"channel\">Channelname.</param>\n        public void RemoveAllListeners(string channel)\n        {\n            BridgeConnector.Socket.Emit(\"removeAllListenersIpcMainChannel\", channel);\n        }\n\n        /// <summary>\n        /// Send a message to the renderer process asynchronously via channel, you can also send\n        /// arbitrary arguments. Arguments will be serialized in JSON internally and hence\n        /// no functions or prototype chain will be included. The renderer process handles it by\n        /// listening for channel with ipcRenderer module.\n        /// </summary>\n        /// <param name=\"browserWindow\">BrowserWindow with channel.</param>\n        /// <param name=\"channel\">Channelname.</param>\n        /// <param name=\"data\">Arguments data.</param>\n        public void Send(BrowserWindow browserWindow, string channel, params object[] data)\n        {\n            BridgeConnector.Socket.Emit(\"sendToIpcRenderer\", browserWindow, channel, data);\n        }\n\n        /// <summary>\n        /// Send a message to the BrowserView renderer process asynchronously via channel, you can also send\n        /// arbitrary arguments. Arguments will be serialized in JSON internally and hence\n        /// no functions or prototype chain will be included. The renderer process handles it by\n        /// listening for channel with ipcRenderer module.\n        /// </summary>\n        /// <param name=\"browserView\">BrowserView with channel.</param>\n        /// <param name=\"channel\">Channelname.</param>\n        /// <param name=\"data\">Arguments data.</param>\n        public void Send(BrowserView browserView, string channel, params object[] data)\n        {\n            BridgeConnector.Socket.Emit(\"sendToIpcRendererBrowserView\", browserView.Id, channel, data);\n        }\n\n        /// <summary>\n        /// Adds a handler for an invokeable IPC. This handler will be called\n        /// whenever a renderer calls ipcRenderer.invoke(channel, ...args).\n        /// </summary>\n        /// <param name=\"channel\">Channelname.</param>\n        /// <param name=\"listener\">Callback Method.</param>\n        public void Handle(string channel, Func<object, object> listener)\n        {\n            BridgeConnector.Socket.Emit(\"registerHandleIpcMainChannel\", channel);\n            BridgeConnector.Socket.On<JsonElement>(channel, (args) =>\n            {\n                var arg = FormatArguments(args);\n                var result = listener(arg);\n                BridgeConnector.Socket.Emit(channel + \"Handle\", result);\n            });\n        }\n\n        /// <summary>\n        /// Adds a handler for an invokeable IPC. This handler will be called\n        /// whenever a renderer calls ipcRenderer.invoke(channel, ...args).\n        /// </summary>\n        /// <param name=\"channel\">Channelname.</param>\n        /// <param name=\"listener\">Callback Method.</param>\n        public void Handle(string channel, Func<object, Task<object>> listener)\n        {\n            BridgeConnector.Socket.Emit(\"registerHandleIpcMainChannel\", channel);\n            BridgeConnector.Socket.On<JsonElement>(channel, (args) =>\n            {\n                Task.Run(async () =>\n                {\n                    var arg = FormatArguments(args);\n                    var result = await listener(arg);\n                    BridgeConnector.Socket.Emit(channel + \"Handle\", result);\n                });\n            });\n        }\n\n        /// <summary>\n        /// Handles a single invokeable IPC message, then removes the listener.\n        /// See ipcMain.handle(channel, listener).\n        /// </summary>\n        /// <param name=\"channel\">Channelname.</param>\n        /// <param name=\"listener\">Callback Method.</param>\n        public void HandleOnce(string channel, Func<object, object> listener)\n        {\n            BridgeConnector.Socket.Emit(\"registerHandleOnceIpcMainChannel\", channel);\n            BridgeConnector.Socket.Once<JsonElement>(channel, (args) =>\n            {\n                var arg = FormatArguments(args);\n                var result = listener(arg);\n                BridgeConnector.Socket.Emit(channel + \"HandleOnce\", result);\n            });\n        }\n\n        /// <summary>\n        /// Handles a single invokeable IPC message, then removes the listener.\n        /// See ipcMain.handle(channel, listener).\n        /// </summary>\n        /// <param name=\"channel\">Channelname.</param>\n        /// <param name=\"listener\">Callback Method.</param>\n        public void HandleOnce(string channel, Func<object, Task<object>> listener)\n        {\n            BridgeConnector.Socket.Emit(\"registerHandleOnceIpcMainChannel\", channel);\n            BridgeConnector.Socket.Once<JsonElement>(channel, (args) =>\n            {\n                Task.Run(async () =>\n                {\n                    var arg = FormatArguments(args);\n                    var result = await listener(arg);\n                    BridgeConnector.Socket.Emit(channel + \"HandleOnce\", result);\n                });\n            });\n        }\n\n        /// <summary>\n        /// Removes any handler for channel, if present.\n        /// </summary>\n        /// <param name=\"channel\">Channelname.</param>\n        public void RemoveHandler(string channel)\n        {\n            BridgeConnector.Socket.Emit(\"removeHandlerIpcMainChannel\", channel);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Menu.cs",
    "content": "using ElectronNET.API.Entities;\nusing ElectronNET.API.Extensions;\nusing ElectronNET.API.Serialization;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing System.Text.Json;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Create native application menus and context menus.\n    /// </summary>\n    public sealed class Menu\n    {\n        private static Menu _menu;\n        private static object _syncRoot = new object();\n\n        internal Menu()\n        {\n        }\n\n        internal static Menu Instance\n        {\n            get\n            {\n                if (_menu == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_menu == null)\n                        {\n                            _menu = new Menu();\n                        }\n                    }\n                }\n\n                return _menu;\n            }\n        }\n\n        /// <summary>\n        /// Gets the menu items.\n        /// </summary>\n        /// <value>\n        /// The menu items.\n        /// </value>\n        public IReadOnlyCollection<MenuItem> MenuItems\n        {\n            get\n            {\n                return _menuItems.AsReadOnly();\n            }\n        }\n\n        private List<MenuItem> _menuItems = new List<MenuItem>();\n\n        /// <summary>\n        /// Sets the application menu.\n        /// </summary>\n        /// <param name=\"menuItems\">The menu items.</param>\n        public void SetApplicationMenu(MenuItem[] menuItems)\n        {\n            _menuItems.Clear();\n\n            menuItems.AddMenuItemsId();\n            menuItems.AddSubmenuTypes();\n\n            BridgeConnector.Socket.Emit(\"menu-setApplicationMenu\", new[] { menuItems });\n            _menuItems.AddRange(menuItems);\n\n            BridgeConnector.Socket.Off(\"menuItemClicked\");\n            BridgeConnector.Socket.On<string>(\"menuItemClicked\", (id) =>\n            {\n                MenuItem menuItem = _menuItems.GetMenuItem(id);\n                menuItem.Click?.Invoke();\n            });\n        }\n\n        /// <summary>\n        /// Gets the context menu items.\n        /// </summary>\n        /// <value>\n        /// The context menu items.\n        /// </value>\n        public IReadOnlyDictionary<int, ReadOnlyCollection<MenuItem>> ContextMenuItems { get; internal set; }\n\n        private Dictionary<int, List<MenuItem>> _contextMenuItems = new Dictionary<int, List<MenuItem>>();\n\n        /// <summary>\n        /// Sets the context menu.\n        /// </summary>\n        /// <param name=\"browserWindow\">The browser window.</param>\n        /// <param name=\"menuItems\">The menu items.</param>\n        public void SetContextMenu(BrowserWindow browserWindow, MenuItem[] menuItems)\n        {\n            menuItems.AddMenuItemsId();\n            menuItems.AddSubmenuTypes();\n\n            BridgeConnector.Socket.Emit(\"menu-setContextMenu\", browserWindow.Id, menuItems);\n\n            if (!_contextMenuItems.ContainsKey(browserWindow.Id))\n            {\n                _contextMenuItems.Add(browserWindow.Id, menuItems.ToList());\n                var x = _contextMenuItems.ToDictionary(kv => kv.Key, kv => kv.Value.AsReadOnly());\n                ContextMenuItems = new ReadOnlyDictionary<int, ReadOnlyCollection<MenuItem>>(x);\n            }\n\n            BridgeConnector.Socket.Off(\"contextMenuItemClicked\");\n            BridgeConnector.Socket.On<JsonElement>(\"contextMenuItemClicked\", (results) =>\n            {\n                var arr = results.EnumerateArray();\n                var e = arr.GetEnumerator();\n                e.MoveNext();\n                var id = e.Current.GetString();\n                e.MoveNext();\n                var browserWindowId = e.Current.GetInt32();\n\n                MenuItem menuItem = _contextMenuItems[browserWindowId].GetMenuItem(id);\n                menuItem.Click?.Invoke();\n            });\n        }\n\n        /// <summary>\n        /// Contexts the menu popup.\n        /// </summary>\n        /// <param name=\"browserWindow\">The browser window.</param>\n        public void ContextMenuPopup(BrowserWindow browserWindow)\n        {\n            BridgeConnector.Socket.Emit(\"menu-contextMenuPopup\", browserWindow.Id);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/NativeTheme.cs",
    "content": "﻿using System;\nusing System.Runtime.Versioning;\nusing System.Threading.Tasks;\nusing ElectronNET.API.Entities;\nusing ElectronNET.API.Extensions;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Read and respond to changes in Chromium's native color theme.\n    /// </summary>\n    public sealed class NativeTheme : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n        protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;\n        protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;\n\n        private static NativeTheme _nativeTheme;\n        private static object _syncRoot = new object();\n\n        internal NativeTheme()\n        {\n        }\n\n        internal static NativeTheme Instance\n        {\n            get\n            {\n                if (_nativeTheme == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_nativeTheme == null)\n                        {\n                            _nativeTheme = new NativeTheme();\n                        }\n                    }\n                }\n\n                return _nativeTheme;\n            }\n        }\n\n        /// <summary>\n        /// Setting this property to <see cref=\"ThemeSourceMode.System\"/> will remove the override and everything will be reset to the OS default. By default 'ThemeSource' is <see cref=\"ThemeSourceMode.System\"/>.\n        /// <para/>\n        /// Settings this property to <see cref=\"ThemeSourceMode.Dark\"/> will have the following effects:\n        /// <list type=\"bullet\">\n        /// <item>\n        /// <description><see cref=\"ShouldUseDarkColorsAsync\"/> will be <see langword=\"true\"/> when accessed</description>\n        /// </item>\n        /// <item>\n        /// <description>Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the dark UI.</description>\n        /// </item>\n        /// <item>\n        /// <description>Any UI the OS renders on macOS including menus, window frames, etc. will use the dark UI.</description>\n        /// </item>\n        /// <item>\n        /// <description>The 'prefers-color-scheme' CSS query will match 'dark' mode.</description>\n        /// </item>\n        /// <item>\n        /// <description>The 'updated' event will be emitted</description>\n        /// </item>\n        /// </list>\n        /// <para/>\n        /// Settings this property to <see cref=\"ThemeSourceMode.Light\"/> will have the following effects:\n        /// <list type=\"bullet\">\n        /// <item>\n        /// <description><see cref=\"ShouldUseDarkColorsAsync\"/> will be <see langword=\"false\"/> when accessed</description>\n        /// </item>\n        /// <item>\n        /// <description>Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the light UI.</description>\n        /// </item>\n        /// <item>\n        /// <description>Any UI the OS renders on macOS including menus, window frames, etc. will use the light UI.</description>\n        /// </item>\n        /// <item>\n        /// <description>The 'prefers-color-scheme' CSS query will match 'light' mode.</description>\n        /// </item>\n        /// <item>\n        /// <description>The 'updated' event will be emitted</description>\n        /// </item>\n        /// </list>\n        /// The usage of this property should align with a classic \"dark mode\" state machine in your application where the user has three options.\n        /// <para/>\n        /// <list type=\"bullet\">\n        /// <item>\n        /// <description>Follow OS: SetThemeSource(ThemeSourceMode.System);</description>\n        /// </item>\n        /// <item>\n        /// <description>Dark Mode: SetThemeSource(ThemeSourceMode.Dark);</description>\n        /// </item>\n        /// <item>\n        /// <description>Light Mode: SetThemeSource(ThemeSourceMode.Light);</description>\n        /// </item>\n        /// </list>\n        /// Your application should then always use <see cref=\"ShouldUseDarkColorsAsync\"/> to determine what CSS to apply.\n        /// </summary>\n        /// <param name=\"themeSourceMode\">The new ThemeSource.</param>\n        public void SetThemeSource(ThemeSourceMode themeSourceMode)\n        {\n            var themeSource = themeSourceMode;\n\n            BridgeConnector.Socket.Emit(\"nativeTheme-themeSource\", themeSource);\n        }\n\n        /// <summary>\n        /// A <see cref=\"ThemeSourceMode\"/> property that can be <see cref=\"ThemeSourceMode.System\"/>, <see cref=\"ThemeSourceMode.Light\"/> or <see cref=\"ThemeSourceMode.Dark\"/>. It is used to override (<seealso cref=\"SetThemeSource\"/>) and\n        /// supercede the value that Chromium has chosen to use internally.\n        /// </summary>\n        public Task<ThemeSourceMode> GetThemeSourceAsync() => this.InvokeAsync<ThemeSourceMode>();\n\n        /// <summary>\n        /// A <see cref=\"bool\"/> for if the OS / Chromium currently has a dark mode enabled or is\n        /// being instructed to show a dark-style UI. If you want to modify this value you\n        /// should use <see cref=\"SetThemeSource\"/>.\n        /// </summary>\n        public Task<bool> ShouldUseDarkColorsAsync() => this.InvokeAsync<bool>();\n\n        /// <summary>\n        /// A <see cref=\"bool\"/> for if the OS / Chromium currently has high-contrast mode enabled or is\n        /// being instructed to show a high-contrast UI.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public Task<bool> ShouldUseHighContrastColorsAsync() => this.InvokeAsync<bool>();\n\n        /// <summary>\n        /// A <see cref=\"bool\"/> for if the OS / Chromium currently has an inverted color scheme or is\n        /// being instructed to use an inverted color scheme.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public Task<bool> ShouldUseInvertedColorSchemeAsync() => this.InvokeAsync<bool>();\n\n        /// <summary>\n        /// Emitted when something in the underlying NativeTheme has changed. This normally means that either the value of <see cref=\"ShouldUseDarkColorsAsync\"/>,\n        /// <see cref=\"ShouldUseHighContrastColorsAsync\"/> or <see cref=\"ShouldUseInvertedColorSchemeAsync\"/> has changed. You will have to check them to determine which one has changed.\n        /// </summary>\n        public event Action Updated\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.API/API/Notification.cs",
    "content": "using ElectronNET.API.Entities;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Create OS desktop notifications\n    /// </summary>\n    public sealed class Notification : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.NoDashUpperFirst;\n        private static Notification _notification;\n        private static object _syncRoot = new object();\n\n        internal Notification()\n        {\n        }\n\n        internal static Notification Instance\n        {\n            get\n            {\n                if (_notification == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_notification == null)\n                        {\n                            _notification = new Notification();\n                        }\n                    }\n                }\n\n                return _notification;\n            }\n        }\n\n        private static List<NotificationOptions> _notificationOptions = new List<NotificationOptions>();\n\n        /// <summary>\n        /// Create OS desktop notifications\n        /// </summary>\n        /// <param name=\"notificationOptions\"></param>\n        public void Show(NotificationOptions notificationOptions)\n        {\n            GenerateIDsForDefinedActions(notificationOptions);\n\n            BridgeConnector.Socket.Emit(\"createNotification\", notificationOptions);\n        }\n\n        private static void GenerateIDsForDefinedActions(NotificationOptions notificationOptions)\n        {\n            bool isActionDefined = false;\n\n            if (notificationOptions.OnShow != null)\n            {\n                notificationOptions.ShowID = Guid.NewGuid().ToString();\n                isActionDefined = true;\n\n                BridgeConnector.Socket.Off(\"NotificationEventShow\");\n                BridgeConnector.Socket.On<string>(\"NotificationEventShow\", (id) => { _notificationOptions.Single(x => x.ShowID == id).OnShow(); });\n            }\n\n            if (notificationOptions.OnClick != null)\n            {\n                notificationOptions.ClickID = Guid.NewGuid().ToString();\n                isActionDefined = true;\n\n                BridgeConnector.Socket.Off(\"NotificationEventClick\");\n                BridgeConnector.Socket.On<string>(\"NotificationEventClick\", (id) => { _notificationOptions.Single(x => x.ClickID == id).OnClick(); });\n            }\n\n            if (notificationOptions.OnClose != null)\n            {\n                notificationOptions.CloseID = Guid.NewGuid().ToString();\n                isActionDefined = true;\n\n                BridgeConnector.Socket.Off(\"NotificationEventClose\");\n                BridgeConnector.Socket.On<string>(\"NotificationEventClose\", (id) => { _notificationOptions.Single(x => x.CloseID == id).OnClose(); });\n            }\n\n            if (notificationOptions.OnReply != null)\n            {\n                notificationOptions.ReplyID = Guid.NewGuid().ToString();\n                isActionDefined = true;\n\n                BridgeConnector.Socket.Off(\"NotificationEventReply\");\n                BridgeConnector.Socket.On<string[]>(\"NotificationEventReply\", (args) => { _notificationOptions.Single(x => x.ReplyID == args[0]).OnReply(args[1]); });\n            }\n\n            if (notificationOptions.OnAction != null)\n            {\n                notificationOptions.ActionID = Guid.NewGuid().ToString();\n                isActionDefined = true;\n\n                BridgeConnector.Socket.Off(\"NotificationEventAction\");\n                BridgeConnector.Socket.On<string[]>(\"NotificationEventAction\", (args) =>\n                {\n                    var opt = _notificationOptions.Single(x => x.ActionID == args[0]);\n                    if (int.TryParse(args[1], out var index))\n                    {\n                        opt.OnAction(index);\n                    }\n                });\n            }\n\n            if (isActionDefined)\n            {\n                _notificationOptions.Add(notificationOptions);\n            }\n        }\n\n        /// <summary>\n        /// Whether or not desktop notifications are supported on the current system.\n        /// </summary>\n        /// <returns></returns>\n        public Task<bool> IsSupportedAsync() => this.InvokeAsync<bool>();\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/PowerMonitor.cs",
    "content": "﻿using System;\nusing System.Runtime.Versioning;\n\n// ReSharper disable InconsistentNaming\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Monitor power state changes..\n    /// </summary>\n    public sealed class PowerMonitor : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n        protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;\n\n        /// <summary>\n        /// Emitted when the system is about to lock the screen.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action OnLockScreen\n        {\n            add => AddEvent(value);\n            remove => RemoveEvent(value);\n        }\n\n        /// <summary>\n        /// Emitted when the system is about to unlock the screen.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action OnUnLockScreen\n        {\n            add => AddEvent(value);\n            remove => RemoveEvent(value);\n        }\n\n        /// <summary>\n        /// Emitted when the system is suspending.\n        /// </summary>\n        public event Action OnSuspend\n        {\n            add => AddEvent(value);\n            remove => RemoveEvent(value);\n        }\n\n        /// <summary>\n        /// Emitted when system is resuming.\n        /// </summary>\n        public event Action OnResume\n        {\n            add => AddEvent(value);\n            remove => RemoveEvent(value);\n        }\n\n        /// <summary>\n        /// Emitted when the system changes to AC power.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action OnAC\n        {\n            add => AddEvent(value);\n            remove => RemoveEvent(value);\n        }\n\n        /// <summary>\n        /// Emitted when system changes to battery power.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action OnBattery\n        {\n            add => AddEvent(value);\n            remove => RemoveEvent(value);\n        }\n\n        /// <summary>\n        /// Emitted when the system is about to reboot or shut down. If the event handler\n        /// invokes `e.preventDefault()`, Electron will attempt to delay system shutdown in\n        /// order for the app to exit cleanly.If `e.preventDefault()` is called, the app\n        /// should exit as soon as possible by calling something like `app.quit()`.\n        /// </summary>\n        [SupportedOSPlatform(\"Linux\")]\n        [SupportedOSPlatform(\"macOS\")]\n        public event Action OnShutdown\n        {\n            add => AddEvent(value);\n            remove => RemoveEvent(value);\n        }\n\n        private static PowerMonitor _powerMonitor;\n        private static object _syncRoot = new object();\n\n        internal PowerMonitor()\n        {\n        }\n\n        internal static PowerMonitor Instance\n        {\n            get\n            {\n                if (_powerMonitor == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_powerMonitor == null)\n                        {\n                            _powerMonitor = new PowerMonitor();\n                        }\n                    }\n                }\n\n                return _powerMonitor;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.API/API/Process.cs",
    "content": "using ElectronNET.API.Entities;\nusing ElectronNET.API.Serialization;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Electron's process object is extended from the Node.js process object. It adds the\n    /// events, properties, and methods.\n    /// </summary>\n    public sealed class Process : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n        protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;\n\n        internal Process()\n        {\n        }\n\n        internal static Process Instance\n        {\n            get\n            {\n                if (_process == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_process == null)\n                        {\n                            _process = new Process();\n                        }\n                    }\n                }\n\n                return _process;\n            }\n        }\n\n        private static Process _process;\n\n        private static readonly object _syncRoot = new();\n\n        /// <summary>\n        /// The process.execPath property returns the absolute pathname of the executable that\n        /// started the Node.js process. Symbolic links, if any, are resolved.\n        /// </summary>\n        public Task<string> ExecPathAsync => this.InvokeAsync<string>();\n\n        /// <summary>\n        /// The process.argv property returns an array containing the command-line arguments passed\n        /// when the Node.js process was launched. The first element will be process.execPath. See\n        /// process.argv0 if access to the original value of argv[0] is needed. The second element\n        /// will be the path to the JavaScript file being executed. The remaining elements will be\n        /// any additional command-line arguments\n        /// </summary>\n        public Task<string[]> ArgvAsync => this.InvokeAsync<string[]>();\n\n        /// <summary>\n        /// The process.execPath property returns the absolute pathname of the executable that\n        /// started the Node.js process. Symbolic links, if any, are resolved.\n        /// </summary>\n        public Task<string> TypeAsync => this.InvokeAsync<string>();\n\n        /// <summary>\n        /// The process.versions property returns an object listing the version strings of\n        /// chrome and electron.\n        /// </summary>\n        public Task<ProcessVersions> VersionsAsync => this.InvokeAsync<ProcessVersions>();\n\n        /// <summary>\n        /// A Boolean. When app is started by being passed as parameter to the default app, this\n        /// property is true in the main process, otherwise it is false.\n        /// </summary>\n        public Task<bool> DefaultAppAsync => this.InvokeAsync<bool>();\n\n        /// <summary>\n        /// A Boolean, true when the current renderer context is the \"main\" renderer frame. If you\n        /// want the ID of the current frame you should use webFrame.routingId\n        /// </summary>\n        public Task<bool> IsMainFrameAsync => this.InvokeAsync<bool>();\n\n        /// <summary>\n        /// A String representing the path to the resources directory.\n        /// </summary>\n        public Task<string> ResourcesPathAsync => this.InvokeAsync<string>();\n\n        /// <summary>\n        /// The number of seconds the current Node.js process has been running. The return value\n        /// includes fractions of a second. Use Math.floor() to get whole seconds.\n        /// </summary>\n        public Task<double> UpTimeAsync => this.InvokeAsync<double>();\n\n        /// <summary>\n        /// The PID of the electron process\n        /// </summary>\n        public Task<int> PidAsync => this.InvokeAsync<int>();\n\n        /// <summary>\n        /// The operating system CPU architecture for which the Node.js binary was compiled\n        /// </summary>\n        public Task<string> ArchAsync => this.InvokeAsync<string>();\n\n        /// <summary>\n        /// A string identifying the operating system platform on which the Node.js process is running\n        /// </summary>\n        public Task<string> PlatformAsync => this.InvokeAsync<string>();\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/QuitEventArgs.cs",
    "content": "﻿namespace ElectronNET.API\n{\n    /// <summary>\n    /// Event arguments for the <see cref=\"App.BeforeQuit\"/> / <see cref=\"App.WillQuit\"/> event.\n    /// </summary>\n    public sealed class QuitEventArgs\n    {\n        /// <summary>\n        /// Will prevent the default behaviour, which is terminating the application.\n        /// </summary>\n        public void PreventDefault()\n        {\n            Electron.App.PreventQuit();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Screen.cs",
    "content": "using ElectronNET.API.Entities;\nusing System;\nusing System.Linq;\nusing System.Runtime.Versioning;\nusing System.Text.Json;\nusing System.Threading.Tasks;\nusing ElectronNET.API.Serialization;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Retrieve information about screen size, displays, cursor position, etc.\n    /// </summary>\n    public sealed class Screen : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n        protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;\n        protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;\n\n        /// <summary>\n        /// Emitted when an new Display has been added.\n        /// </summary>\n        public event Action<Display> OnDisplayAdded\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when oldDisplay has been removed.\n        /// </summary>\n        public event Action<Display> OnDisplayRemoved\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Emitted when one or more metrics change in a display.\n        /// The changedMetrics is an array of strings that describe the changes.\n        /// Possible changes are bounds, workArea, scaleFactor and rotation.\n        /// </summary>\n        public event Action<Display, string[]> OnDisplayMetricsChanged\n        {\n            add\n            {\n                if (_onDisplayMetricsChanged == null)\n                {\n                    BridgeConnector.Socket.On<JsonElement>(\"screen-display-metrics-changed\" + GetHashCode(), (args) =>\n                    {\n                        var arr = args.EnumerateArray().ToArray();\n                        var display = arr[0].Deserialize(ElectronJsonContext.Default.Display);\n                        var metrics = arr[1].Deserialize<string[]>(ElectronJson.Options);\n\n                        _onDisplayMetricsChanged(display, metrics);\n                    });\n\n                    BridgeConnector.Socket.Emit(\"register-screen-display-metrics-changed\", GetHashCode());\n                }\n\n                _onDisplayMetricsChanged += value;\n            }\n            remove\n            {\n                _onDisplayMetricsChanged -= value;\n\n                if (_onDisplayMetricsChanged == null)\n                {\n                    BridgeConnector.Socket.Off(\"screen-display-metrics-changed\" + GetHashCode());\n                }\n            }\n        }\n\n        private event Action<Display, string[]> _onDisplayMetricsChanged;\n\n        private static Screen _screen;\n        private static object _syncRoot = new object();\n\n        internal Screen()\n        {\n        }\n\n        internal static Screen Instance\n        {\n            get\n            {\n                if (_screen == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_screen == null)\n                        {\n                            _screen = new Screen();\n                        }\n                    }\n                }\n\n                return _screen;\n            }\n        }\n\n        /// <summary>\n        /// The current absolute position of the mouse pointer.\n        /// </summary>\n        /// <returns></returns>\n        public Task<Point> GetCursorScreenPointAsync() => this.InvokeAsync<Point>();\n\n        /// <summary>\n        /// macOS: The height of the menu bar in pixels.\n        /// </summary>\n        /// <returns>The height of the menu bar in pixels.</returns>\n        [SupportedOSPlatform(\"macOS\")]\n        public Task<Rectangle> GetMenuBarWorkAreaAsync() => this.InvokeAsync<Rectangle>();\n\n        /// <summary>\n        /// The primary display.\n        /// </summary>\n        /// <returns></returns>\n        public Task<Display> GetPrimaryDisplayAsync() => this.InvokeAsync<Display>();\n\n        /// <summary>\n        /// An array of displays that are currently available.\n        /// </summary>\n        /// <returns>An array of displays that are currently available.</returns>\n        public Task<Display[]> GetAllDisplaysAsync() => this.InvokeAsync<Display[]>();\n\n        /// <summary>\n        /// An array of displays that are currently available.\n        /// </summary>\n        /// <param name=\"invocationTimeout\">The invocation timeout.</param>\n        /// <returns>\n        /// An array of displays that are currently available.\n        /// </returns>\n        public Task<Display[]> GetAllDisplaysAsync(TimeSpan invocationTimeout) => this.InvokeAsyncWithTimeout<Display[]>(invocationTimeout);\n\n        /// <summary>\n        /// The display nearest the specified point.\n        /// </summary>\n        /// <returns>The display nearest the specified point.</returns>\n        public Task<Display> GetDisplayNearestPointAsync(Point point) => this.InvokeAsync<Display>(point);\n\n        /// <summary>\n        /// The display that most closely intersects the provided bounds.\n        /// </summary>\n        /// <param name=\"rectangle\"></param>\n        /// <returns>The display that most closely intersects the provided bounds.</returns>\n        public Task<Display> GetDisplayMatchingAsync(Rectangle rectangle) => this.InvokeAsync<Display>(rectangle);\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Session.cs",
    "content": "using ElectronNET.API.Entities;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Manage browser sessions, cookies, cache, proxy settings, etc.\n    /// </summary>\n    public class Session\n    {\n        /// <summary>\n        /// Gets the identifier.\n        /// </summary>\n        /// <value>\n        /// The identifier.\n        /// </value>\n        public int Id { get; private set; }\n\n        /// <summary>\n        /// Query and modify a session's cookies.\n        /// </summary>\n        public Cookies Cookies { get; }\n\n        public WebRequest WebRequest { get; private set; }\n\n        internal Session(int id)\n        {\n            Id = id;\n            Cookies = new Cookies(id);\n            WebRequest = new WebRequest(id);\n        }\n\n        /// <summary>\n        /// Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate authentication.\n        /// </summary>\n        /// <param name=\"domains\">A comma-separated list of servers for which integrated authentication is enabled.</param>\n        public void AllowNTLMCredentialsForDomains(string domains)\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-allowNTLMCredentialsForDomains\", Id, domains);\n        }\n\n        /// <summary>\n        /// Clears the session’s HTTP authentication cache.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        /// <returns></returns>\n        public Task ClearAuthCacheAsync(RemovePassword options)\n        {\n            var tcs = new TaskCompletionSource();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once(\"webContents-session-clearAuthCache-completed\" + guid, () => tcs.SetResult());\n            BridgeConnector.Socket.Emit(\"webContents-session-clearAuthCache\", Id, options, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Clears the session’s HTTP authentication cache.\n        /// </summary>\n        public Task ClearAuthCacheAsync()\n        {\n            var tcs = new TaskCompletionSource();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once(\"webContents-session-clearAuthCache-completed\" + guid, () => tcs.SetResult());\n            BridgeConnector.Socket.Emit(\"webContents-session-clearAuthCache\", Id, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Clears the session’s HTTP cache.\n        /// </summary>\n        /// <returns></returns>\n        public Task ClearCacheAsync()\n        {\n            var tcs = new TaskCompletionSource();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once(\"webContents-session-clearCache-completed\" + guid, () => tcs.SetResult());\n            BridgeConnector.Socket.Emit(\"webContents-session-clearCache\", Id, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Clears the host resolver cache.\n        /// </summary>\n        /// <returns></returns>\n        public Task ClearHostResolverCacheAsync()\n        {\n            var tcs = new TaskCompletionSource();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once(\"webContents-session-clearHostResolverCache-completed\" + guid, () => tcs.SetResult());\n            BridgeConnector.Socket.Emit(\"webContents-session-clearHostResolverCache\", Id, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Clears the data of web storages.\n        /// </summary>\n        /// <returns></returns>\n        public Task ClearStorageDataAsync()\n        {\n            var tcs = new TaskCompletionSource();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once(\"webContents-session-clearStorageData-completed\" + guid, () => tcs.SetResult());\n            BridgeConnector.Socket.Emit(\"webContents-session-clearStorageData\", Id, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Clears the data of web storages.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        /// <returns></returns>\n        public Task ClearStorageDataAsync(ClearStorageDataOptions options)\n        {\n            var tcs = new TaskCompletionSource();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once(\"webContents-session-clearStorageData-options-completed\" + guid, () => tcs.SetResult());\n            BridgeConnector.Socket.Emit(\"webContents-session-clearStorageData-options\", Id, options, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Allows resuming cancelled or interrupted downloads from previous Session. The\n        /// API will generate a DownloadItem that can be accessed with the will-download\n        /// event. The DownloadItem will not have any WebContents associated with it and the\n        /// initial state will be interrupted. The download will start only when the resume\n        /// API is called on the DownloadItem.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        public void CreateInterruptedDownload(CreateInterruptedDownloadOptions options)\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-createInterruptedDownload\", Id, options);\n        }\n\n        /// <summary>\n        /// Disables any network emulation already active for the session. Resets to the\n        /// original network configuration.\n        /// </summary>\n        public void DisableNetworkEmulation()\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-disableNetworkEmulation\", Id);\n        }\n\n        /// <summary>\n        /// Emulates network with the given configuration for the session.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        public void EnableNetworkEmulation(EnableNetworkEmulationOptions options)\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-enableNetworkEmulation\", Id, options);\n        }\n\n        /// <summary>\n        /// Writes any unwritten DOMStorage data to disk.\n        /// </summary>\n        public void FlushStorageData()\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-flushStorageData\", Id);\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"identifier\"></param>\n        /// <returns></returns>\n        public Task<int[]> GetBlobDataAsync(string identifier)\n        {\n            var tcs = new TaskCompletionSource<int[]>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<int[]>(\"webContents-session-getBlobData-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-getBlobData\", Id, identifier, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Get session's current cache size.\n        /// </summary>\n        /// <returns>Callback is invoked with the session's current cache size.</returns>\n        public Task<int> GetCacheSizeAsync()\n        {\n            var tcs = new TaskCompletionSource<int>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<int>(\"webContents-session-getCacheSize-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-getCacheSize\", Id, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <returns></returns>\n        public Task<string[]> GetPreloadsAsync()\n        {\n            var tcs = new TaskCompletionSource<string[]>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<string[]>(\"webContents-session-getPreloads-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-getPreloads\", Id, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <returns></returns>\n        public Task<string> GetUserAgent()\n        {\n            var tcs = new TaskCompletionSource<string>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<string>(\"webContents-session-getUserAgent-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-getUserAgent\", Id, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Resolves the proxy information for url. The callback will be called with\n        /// callback(proxy) when the request is performed.\n        /// </summary>\n        /// <param name=\"url\"></param>\n        /// <returns></returns>\n        public Task<string> ResolveProxyAsync(string url)\n        {\n            var tcs = new TaskCompletionSource<string>();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once<string>(\"webContents-session-resolveProxy-completed\" + guid, tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-resolveProxy\", Id, url, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Sets download saving directory. By default, the download directory will be the\n        /// Downloads under the respective app folder.\n        /// </summary>\n        /// <param name=\"path\"></param>\n        public void SetDownloadPath(string path)\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-setDownloadPath\", Id, path);\n        }\n\n        /// <summary>\n        /// Adds scripts that will be executed on ALL web contents that are associated with\n        /// this session just before normal preload scripts run.\n        /// </summary>\n        /// <param name=\"preloads\"></param>\n        public void SetPreloads(string[] preloads)\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-setPreloads\", Id, preloads);\n        }\n\n        /// <summary>\n        /// Sets the proxy settings. When pacScript and proxyRules are provided together,\n        /// the proxyRules option is ignored and pacScript configuration is applied.\n        /// </summary>\n        /// <param name=\"config\"></param>\n        /// <returns></returns>\n        public Task SetProxyAsync(ProxyConfig config)\n        {\n            var tcs = new TaskCompletionSource();\n            string guid = Guid.NewGuid().ToString();\n\n            BridgeConnector.Socket.Once(\"webContents-session-setProxy-completed\" + guid, () => tcs.SetResult());\n            BridgeConnector.Socket.Emit(\"webContents-session-setProxy\", Id, config, guid);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Overrides the userAgent for this session. This doesn't affect existing WebContents, and\n        /// each WebContents can use webContents.setUserAgent to override the session-wide\n        /// user agent.\n        /// </summary>\n        /// <param name=\"userAgent\"></param>\n        public void SetUserAgent(string userAgent)\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-setUserAgent\", Id, userAgent);\n        }\n\n        /// <summary>\n        /// Overrides the userAgent and acceptLanguages for this session. The\n        /// acceptLanguages must a comma separated ordered list of language codes, for\n        /// example \"en-US,fr,de,ko,zh-CN,ja\". This doesn't affect existing WebContents, and\n        /// each WebContents can use webContents.setUserAgent to override the session-wide\n        /// user agent.\n        /// </summary>\n        /// <param name=\"userAgent\"></param>\n        /// <param name=\"acceptLanguages\">The\n        /// acceptLanguages must a comma separated ordered list of language codes, for\n        /// example \"en-US,fr,de,ko,zh-CN,ja\".</param>\n        public void SetUserAgent(string userAgent, string acceptLanguages)\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-setUserAgent\", Id, userAgent, acceptLanguages);\n        }\n\n        /// <summary>\n        /// The keys are the extension names and each value is an object containing name and version properties.\n        /// Note: This API cannot be called before the ready event of the app module is emitted.\n        /// </summary>\n        /// <returns></returns>\n        public Task<ChromeExtensionInfo[]> GetAllExtensionsAsync()\n        {\n            var tcs = new TaskCompletionSource<ChromeExtensionInfo[]>();\n\n            BridgeConnector.Socket.Once<ChromeExtensionInfo[]>(\"webContents-session-getAllExtensions-completed\", tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-getAllExtensions\", Id);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Remove Chrome extension with the specified name.\n        /// Note: This API cannot be called before the ready event of the app module is emitted.\n        /// </summary>\n        /// <param name=\"name\">Name of the Chrome extension to remove</param>\n        public void RemoveExtension(string name)\n        {\n            BridgeConnector.Socket.Emit(\"webContents-session-removeExtension\", Id, name);\n        }\n\n        /// <summary>\n        /// resolves when the extension is loaded.\n        ///\n        /// This method will raise an exception if the extension could not be loaded.If\n        /// there are warnings when installing the extension (e.g. if the extension requests\n        /// an API that Electron does not support) then they will be logged to the console.\n        ///\n        /// Note that Electron does not support the full range of Chrome extensions APIs.\n        /// See Supported Extensions APIs for more details on what is supported.\n        ///\n        /// Note that in previous versions of Electron, extensions that were loaded would be\n        /// remembered for future runs of the application.This is no longer the case:\n        /// `loadExtension` must be called on every boot of your app if you want the\n        /// extension to be loaded.\n        ///\n        /// This API does not support loading packed (.crx) extensions.\n        ///\n        ///** Note:** This API cannot be called before the `ready` event of the `app` module\n        /// is emitted.\n        ///\n        ///** Note:** Loading extensions into in-memory(non-persistent) sessions is not supported and will throw an error.\n        /// </summary>\n        /// <param name=\"path\">Path to the Chrome extension</param>\n        /// <param name=\"allowFileAccess\">Whether to allow the extension to read local files over `file://` protocol and\n        /// inject content scripts into `file://` pages. This is required e.g. for loading\n        /// devtools extensions on `file://` URLs. Defaults to false.</param>\n        /// <returns></returns>\n        public Task<Extension> LoadExtensionAsync(string path, bool allowFileAccess = false)\n        {\n            var tcs = new TaskCompletionSource<Extension>();\n\n            BridgeConnector.Socket.Once<Extension>(\"webContents-session-loadExtension-completed\", tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"webContents-session-loadExtension\", Id, path, allowFileAccess);\n\n            return tcs.Task;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Shell.cs",
    "content": "using System.Runtime.Versioning;\nusing System.Threading.Tasks;\nusing ElectronNET.API.Entities;\nusing ElectronNET.API.Extensions;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Manage files and URLs using their default applications.\n    /// </summary>\n    public sealed class Shell\n    {\n        private static Shell _shell;\n        private static object _syncRoot = new object();\n\n        internal Shell()\n        {\n        }\n\n        internal static Shell Instance\n        {\n            get\n            {\n                if (_shell == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_shell == null)\n                        {\n                            _shell = new Shell();\n                        }\n                    }\n                }\n\n                return _shell;\n            }\n        }\n\n        /// <summary>\n        /// Show the given file in a file manager. If possible, select the file.\n        /// </summary>\n        /// <param name=\"fullPath\">The full path to the directory / file.</param>\n        public Task ShowItemInFolderAsync(string fullPath)\n        {\n            BridgeConnector.Socket.Emit(\"shell-showItemInFolder\", fullPath);\n\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Open the given file in the desktop's default manner.\n        /// </summary>\n        /// <param name=\"path\">The path to the directory / file.</param>\n        /// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref=\"string.Empty\"/>.</returns>\n        public Task<string> OpenPathAsync(string path)\n        {\n            var tcs = new TaskCompletionSource<string>();\n\n            BridgeConnector.Socket.Once<string>(\"shell-openPathCompleted\", tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"shell-openPath\", path);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Open the given external protocol URL in the desktop’s default manner.\n        /// (For example, mailto: URLs in the user’s default mail agent).\n        /// </summary>\n        /// <param name=\"url\">Max 2081 characters on windows.</param>\n        /// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref=\"string.Empty\"/>.</returns>\n        public Task<string> OpenExternalAsync(string url)\n        {\n            return OpenExternalAsync(url, null);\n        }\n\n        /// <summary>\n        /// Open the given external protocol URL in the desktop’s default manner.\n        /// (For example, mailto: URLs in the user’s default mail agent).\n        /// </summary>\n        /// <param name=\"url\">Max 2081 characters on windows.</param>\n        /// <param name=\"options\">Controls the behavior of OpenExternal.</param>\n        /// <returns>The error message corresponding to the failure if a failure occurred, otherwise <see cref=\"string.Empty\"/>.</returns>\n        public Task<string> OpenExternalAsync(string url, OpenExternalOptions options)\n        {\n            var tcs = new TaskCompletionSource<string>();\n\n            BridgeConnector.Socket.Once<string>(\"shell-openExternalCompleted\", tcs.SetResult);\n\n            if (options == null)\n            {\n                BridgeConnector.Socket.Emit(\"shell-openExternal\", url);\n            }\n            else\n            {\n                BridgeConnector.Socket.Emit(\"shell-openExternal\", url, options);\n            }\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Move the given file to trash and returns a <see cref=\"bool\"/> status for the operation.\n        /// </summary>\n        /// <param name=\"fullPath\">The full path to the directory / file.</param>\n        /// <returns> Whether the item was successfully moved to the trash.</returns>\n        public Task<bool> TrashItemAsync(string fullPath)\n        {\n            var tcs = new TaskCompletionSource<bool>();\n\n            BridgeConnector.Socket.Once<bool>(\"shell-trashItem-completed\", tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"shell-trashItem\", fullPath);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Play the beep sound.\n        /// </summary>\n        public void Beep()\n        {\n            BridgeConnector.Socket.Emit(\"shell-beep\");\n        }\n\n        /// <summary>\n        /// Creates or updates a shortcut link at shortcutPath.\n        /// </summary>\n        /// <param name=\"shortcutPath\">The path to the shortcut.</param>\n        /// <param name=\"operation\">Default is <see cref=\"ShortcutLinkOperation.Create\"/></param>\n        /// <param name=\"options\">Structure of a shortcut.</param>\n        /// <returns>Whether the shortcut was created successfully.</returns>\n        [SupportedOSPlatform(\"Windows\")]\n        public Task<bool> WriteShortcutLinkAsync(string shortcutPath, ShortcutLinkOperation operation, ShortcutDetails options)\n        {\n            var tcs = new TaskCompletionSource<bool>();\n\n            BridgeConnector.Socket.Once<bool>(\"shell-writeShortcutLinkCompleted\", tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"shell-writeShortcutLink\", shortcutPath, operation, options);\n\n            return tcs.Task;\n        }\n\n        /// <summary>\n        /// Resolves the shortcut link at shortcutPath.\n        /// An exception will be thrown when any error happens.\n        /// </summary>\n        /// <param name=\"shortcutPath\">The path tot the shortcut.</param>\n        /// <returns><see cref=\"ShortcutDetails\"/> of the shortcut.</returns>\n        [SupportedOSPlatform(\"Windows\")]\n        public Task<ShortcutDetails> ReadShortcutLinkAsync(string shortcutPath)\n        {\n            var tcs = new TaskCompletionSource<ShortcutDetails>();\n\n            BridgeConnector.Socket.Once<ShortcutDetails>(\"shell-readShortcutLinkCompleted\", tcs.SetResult);\n            BridgeConnector.Socket.Emit(\"shell-readShortcutLink\", shortcutPath);\n\n            return tcs.Task;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/Tray.cs",
    "content": "using ElectronNET.API.Entities;\nusing ElectronNET.API.Extensions;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.Versioning;\nusing System.Text.Json;\nusing System.Threading.Tasks;\nusing ElectronNET.API.Serialization;\n\n// ReSharper disable InconsistentNaming\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// Add icons and context menus to the system's notification area.\n    /// </summary>\n    public sealed class Tray : ApiBase\n    {\n        protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n        protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower;\n\n        /// <summary>\n        /// Emitted when the tray icon is clicked.\n        /// </summary>\n        public event Action<TrayClickEventArgs, Rectangle> OnClick\n        {\n            add\n            {\n                if (_click == null)\n                {\n                    BridgeConnector.Socket.On<JsonElement>(\"tray-click\" + GetHashCode(), (result) =>\n                    {\n                        var array = result.EnumerateArray().ToArray();\n                        var trayClickEventArgs = array[0].Deserialize(ElectronJsonContext.Default.TrayClickEventArgs);\n                        var bounds = array[1].Deserialize(ElectronJsonContext.Default.Rectangle);\n                        _click(trayClickEventArgs, bounds);\n                    });\n\n                    BridgeConnector.Socket.Emit(\"register-tray-click\", GetHashCode());\n                }\n\n                _click += value;\n            }\n            remove\n            {\n                _click -= value;\n\n                if (_click == null)\n                {\n                    BridgeConnector.Socket.Off(\"tray-click\" + GetHashCode());\n                }\n            }\n        }\n\n        private event Action<TrayClickEventArgs, Rectangle> _click;\n\n        /// <summary>\n        /// macOS, Windows: Emitted when the tray icon is right clicked.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action<TrayClickEventArgs, Rectangle> OnRightClick\n        {\n            add\n            {\n                if (_rightClick == null)\n                {\n                    BridgeConnector.Socket.On<JsonElement>(\"tray-right-click\" + GetHashCode(), (result) =>\n                    {\n                        var array = result.EnumerateArray().ToArray();\n                        var trayClickEventArgs = array[0].Deserialize(ElectronJsonContext.Default.TrayClickEventArgs);\n                        var bounds = array[1].Deserialize(ElectronJsonContext.Default.Rectangle);\n                        _rightClick(trayClickEventArgs, bounds);\n                    });\n\n                    BridgeConnector.Socket.Emit(\"register-tray-right-click\", GetHashCode());\n                }\n\n                _rightClick += value;\n            }\n            remove\n            {\n                _rightClick -= value;\n\n                if (_rightClick == null)\n                {\n                    BridgeConnector.Socket.Off(\"tray-right-click\" + GetHashCode());\n                }\n            }\n        }\n\n        private event Action<TrayClickEventArgs, Rectangle> _rightClick;\n\n        /// <summary>\n        /// macOS, Windows: Emitted when the tray icon is double clicked.\n        /// </summary>\n        [SupportedOSPlatform(\"macOS\")]\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action<TrayClickEventArgs, Rectangle> OnDoubleClick\n        {\n            add\n            {\n                if (_doubleClick == null)\n                {\n                    BridgeConnector.Socket.On<JsonElement>(\"tray-double-click\" + GetHashCode(), (result) =>\n                    {\n                        var array = result.EnumerateArray().ToArray();\n                        var trayClickEventArgs = array[0].Deserialize(ElectronJsonContext.Default.TrayClickEventArgs);\n                        var bounds = array[1].Deserialize(ElectronJsonContext.Default.Rectangle);\n                        _doubleClick(trayClickEventArgs, bounds);\n                    });\n\n                    BridgeConnector.Socket.Emit(\"register-tray-double-click\", GetHashCode());\n                }\n\n                _doubleClick += value;\n            }\n            remove\n            {\n                _doubleClick -= value;\n\n                if (_doubleClick == null)\n                {\n                    BridgeConnector.Socket.Off(\"tray-double-click\" + GetHashCode());\n                }\n            }\n        }\n\n        private event Action<TrayClickEventArgs, Rectangle> _doubleClick;\n\n        /// <summary>\n        /// Windows: Emitted when the tray balloon shows.\n        /// </summary>\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action OnBalloonShow\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Windows: Emitted when the tray balloon is clicked.\n        /// </summary>\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action OnBalloonClick\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        /// <summary>\n        /// Windows: Emitted when the tray balloon is closed\n        /// because of timeout or user manually closes it.\n        /// </summary>\n        [SupportedOSPlatform(\"Windows\")]\n        public event Action OnBalloonClosed\n        {\n            add => AddEvent(value, GetHashCode());\n            remove => RemoveEvent(value, GetHashCode());\n        }\n\n        // TODO: Implement macOS Events\n\n        private static Tray _tray;\n        private static readonly object _syncRoot = new();\n\n        internal Tray()\n        {\n        }\n\n        internal static Tray Instance\n        {\n            get\n            {\n                if (_tray == null)\n                {\n                    lock (_syncRoot)\n                    {\n                        if (_tray == null)\n                        {\n                            _tray = new Tray();\n                        }\n                    }\n                }\n\n                return _tray;\n            }\n        }\n\n        /// <summary>\n        /// Gets the menu items.\n        /// </summary>\n        /// <value>\n        /// The menu items.\n        /// </value>\n        public IReadOnlyCollection<MenuItem> MenuItems => _items.AsReadOnly();\n\n        private readonly List<MenuItem> _items = new();\n\n        /// <summary>\n        /// Shows the Traybar.\n        /// </summary>\n        /// <param name=\"image\">The image.</param>\n        /// <param name=\"menuItem\">The menu item.</param>\n        public async Task Show(string image, MenuItem menuItem)\n        {\n            await this.Show(image, new MenuItem[] { menuItem }).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Shows the Traybar.\n        /// </summary>\n        /// <param name=\"image\">The image.</param>\n        /// <param name=\"menuItems\">The menu items.</param>\n        public async Task Show(string image, MenuItem[] menuItems)\n        {\n            menuItems.AddMenuItemsId();\n            await BridgeConnector.Socket.Emit(\"create-tray\", image, menuItems).ConfigureAwait(false);\n            _items.Clear();\n            _items.AddRange(menuItems);\n\n            RegisterMenuItemClickedHandler();\n        }\n\n        /// <summary>\n        /// Sets the tray menu items.\n        /// </summary>\n        /// <remarks>Calling this method updates the context menu with the specified items. Any previously\n        /// set menu items will be replaced.</remarks>\n        /// <param name=\"menuItems\">An array of <see cref=\"MenuItem\"/> objects representing the menu items to display in the tray menu.\n        /// Cannot be null.</param>\n        public async Task SetMenuItems(MenuItem[] menuItems)\n        {\n            menuItems.AddMenuItemsId();\n            await BridgeConnector.Socket.Emit(\"set-contextMenu\", new object[] { menuItems }).ConfigureAwait(false);\n            _items.Clear();\n            _items.AddRange(menuItems);\n\n            RegisterMenuItemClickedHandler();\n        }\n\n        private void RegisterMenuItemClickedHandler()\n        {\n            BridgeConnector.Socket.Off(\"trayMenuItemClicked\");\n            BridgeConnector.Socket.On<string>(\"trayMenuItemClicked\", (id) =>\n            {\n                MenuItem menuItem = _items.GetMenuItem(id);\n                menuItem?.Click?.Invoke();\n            });\n        }\n\n        /// <summary>\n        /// Shows the Traybar (empty).\n        /// </summary>\n        /// <param name=\"image\">The image.</param>\n        public async Task Show(string image)\n        {\n            await BridgeConnector.Socket.Emit(\"create-tray\", image).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Destroys the tray icon immediately.\n        /// </summary>\n        public async Task Destroy()\n        {\n            await BridgeConnector.Socket.Emit(\"tray-destroy\").ConfigureAwait(false);\n            _items.Clear();\n        }\n\n        /// <summary>\n        /// Sets the image associated with this tray icon.\n        /// </summary>\n        /// <param name=\"image\"></param>\n        public async Task SetImage(string image)\n        {\n            await BridgeConnector.Socket.Emit(\"tray-setImage\", image).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Sets the image associated with this tray icon when pressed on macOS.\n        /// </summary>\n        /// <param name=\"image\"></param>\n        [SupportedOSPlatform(\"macOS\")]\n        public async Task SetPressedImage(string image)\n        {\n            await BridgeConnector.Socket.Emit(\"tray-setPressedImage\", image).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Sets the hover text for this tray icon.\n        /// </summary>\n        /// <param name=\"toolTip\"></param>\n        public async Task SetToolTip(string toolTip)\n        {\n            await BridgeConnector.Socket.Emit(\"tray-setToolTip\", toolTip).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// macOS: Sets the title displayed aside of the tray icon in the status bar.\n        /// </summary>\n        /// <param name=\"title\"></param>\n        [SupportedOSPlatform(\"macOS\")]\n        public async Task SetTitle(string title)\n        {\n            await BridgeConnector.Socket.Emit(\"tray-setTitle\", title).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Windows: Displays a tray balloon.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        [SupportedOSPlatform(\"Windows\")]\n        public async Task DisplayBalloon(DisplayBalloonOptions options)\n        {\n            await BridgeConnector.Socket.Emit(\"tray-displayBalloon\", options).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Whether the tray icon is destroyed.\n        /// </summary>\n        /// <returns></returns>\n        public async Task<bool> IsDestroyedAsync()\n        {\n            var tcs = new TaskCompletionSource<bool>();\n\n            BridgeConnector.Socket.Once<bool>(\"tray-isDestroyedCompleted\", tcs.SetResult);\n            await BridgeConnector.Socket.Emit(\"tray-isDestroyed\").ConfigureAwait(false);\n\n            return await tcs.Task.ConfigureAwait(false);\n        }\n\n\n        private const string ModuleName = \"tray\";\n\n        /// <summary>\n        /// Subscribe to an unmapped event on the <see cref=\"Tray\"/> module.\n        /// </summary>\n        /// <param name=\"eventName\">The event name</param>\n        /// <param name=\"action\">The handler</param>\n        public void On(string eventName, Action action)\n            => Events.Instance.On(ModuleName, eventName, action);\n\n        /// <summary>\n        /// Subscribe to an unmapped event on the <see cref=\"Tray\"/> module.\n        /// </summary>\n        /// <param name=\"eventName\">The event name</param>\n        /// <param name=\"action\">The handler</param>\n        public async Task On<T>(string eventName, Action<T> action)\n            => await Events.Instance.On(ModuleName, eventName, action).ConfigureAwait(false);\n\n        /// <summary>\n        /// Subscribe to an unmapped event on the <see cref=\"Tray\"/> module once.\n        /// </summary>\n        /// <param name=\"eventName\">The event name</param>\n        /// <param name=\"action\">The handler</param>\n        public void Once(string eventName, Action action)\n            => Events.Instance.Once(ModuleName, eventName, action);\n\n        /// <summary>\n        /// Subscribe to an unmapped event on the <see cref=\"Tray\"/> module once.\n        /// </summary>\n        /// <param name=\"eventName\">The event name</param>\n        /// <param name=\"action\">The handler</param>\n        public async Task Once<T>(string eventName, Action<T> action)\n            => await Events.Instance.Once(ModuleName, eventName, action).ConfigureAwait(false);\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.API/API/WebContents.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing ElectronNET.API.Entities;\nusing ElectronNET.Common;\n\n// ReSharper disable InconsistentNaming\n\nnamespace ElectronNET.API;\n\n/// <summary>\n/// Render and control web pages.\n/// </summary>\npublic class WebContents : ApiBase\n{\n    protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst;\n    protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst;\n    protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.CamelCase;\n\n    /// <summary>\n    /// Gets the identifier.\n    /// </summary>\n    /// <value>\n    /// The identifier.\n    /// </value>\n    public override int Id { get; protected set; }\n\n    /// <summary>\n    /// Manage browser sessions, cookies, cache, proxy settings, etc.\n    /// </summary>\n    public Session Session { get; internal set; }\n\n    /// <summary>\n    /// Emitted when the renderer process crashes or is killed.\n    /// </summary>\n    public event Action<bool> OnCrashed\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the navigation is done, i.e. the spinner of the tab has\n    /// stopped spinning, and the onload event was dispatched.\n    /// </summary>\n    public event Action OnDidFinishLoad\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when any frame (including main) starts navigating.\n    /// </summary>\n    public event Action<string> OnDidStartNavigation\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when a main frame navigation is done.\n    /// This event is not emitted for in-page navigations, such as clicking anchor links or updating the window.location.hash. Use did-navigate-in-page event for this purpose.\n    /// </summary>\n    public event Action<OnDidNavigateInfo> OnDidNavigate\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when a server side redirect occurs during navigation. For example a 302 redirect.\n    /// This event will be emitted after OnDidStartNavigation and always before the OnDidRedirectNavigation event for the same navigation.\n    /// </summary>\n    public event Action<string> OnWillRedirect\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted after a server side redirect occurs during navigation. For example a 302 redirect.\n    /// </summary>\n    public event Action<string> OnDidRedirectNavigation\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// This event is like OnDidFinishLoad but emitted when the load failed.\n    /// </summary>\n    public event Action<OnDidFailLoadInfo> OnDidFailLoad\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when an input event is sent to the WebContents.\n    /// </summary>\n    public event Action<InputEvent> InputEvent\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    /// <summary>\n    /// Emitted when the document in the top-level frame is loaded.\n    /// </summary>\n    public event Action OnDomReady\n    {\n        add => AddEvent(value, Id);\n        remove => RemoveEvent(value, Id);\n    }\n\n    internal WebContents(int id)\n    {\n        Id = id;\n        Session = new Session(id);\n    }\n\n    /// <summary>\n    /// Opens the devtools.\n    /// </summary>\n    public void OpenDevTools()\n    {\n        BridgeConnector.Socket.Emit(\"webContents-openDevTools\", Id);\n    }\n\n    /// <summary>\n    /// Opens the devtools.\n    /// </summary>\n    /// <param name=\"openDevToolsOptions\"></param>\n    public void OpenDevTools(OpenDevToolsOptions openDevToolsOptions)\n    {\n        BridgeConnector.Socket.Emit(\"webContents-openDevTools\", Id, openDevToolsOptions);\n    }\n\n    /// <summary>\n    /// Toggles the devtools.\n    /// </summary>\n    public void ToggleDevTools()\n    {\n        BridgeConnector.Socket.Emit(\"webContents-toggleDevTools\", Id);\n    }\n\n    /// <summary>\n    /// Closes the devtools.\n    /// </summary>\n    public void CloseDevTools()\n    {\n        BridgeConnector.Socket.Emit(\"webContents-closeDevTools\", Id);\n    }\n\n    /// <summary>\n    /// Returns boolean - Whether the devtools is opened.\n    /// </summary>\n    /// <returns></returns>\n    public bool IsDevToolsOpened()\n    {\n        return Task.Run(() => InvokeAsync<bool>()).Result;\n    }\n\n    /// <summary>\n    /// Returns boolean - Whether the devtools view is focused.\n    /// </summary>\n    /// <returns></returns>\n    public bool IsDevToolsFocused()\n    {\n        return Task.Run(() => InvokeAsync<bool>()).Result;\n    }\n\n    /// <summary>\n    /// Get system printers.\n    /// </summary>\n    /// <returns>printers</returns>\n    public Task<PrinterInfo[]> GetPrintersAsync() => this.InvokeAsyncWithTimeout<PrinterInfo[]>(8.seconds());\n\n    /// <summary>\n    /// Prints window's web page.\n    /// </summary>\n    /// <param name=\"options\"></param>\n    /// <returns>success</returns>\n    public Task<bool> PrintAsync(PrintOptions options) => this.InvokeAsync<bool>(options);\n\n    /// <summary>\n    /// Prints window's web page.\n    /// </summary>\n    /// <returns>success</returns>\n    public Task<bool> PrintAsync() => this.InvokeAsync<bool>(string.Empty);\n\n    /// <summary>\n    /// Prints window's web page as PDF with Chromium's preview printing custom\n    /// settings.The landscape will be ignored if @page CSS at-rule is used in the web page.\n    /// By default, an empty options will be regarded as: Use page-break-before: always;\n    /// CSS style to force to print to a new page.\n    /// </summary>\n    /// <param name=\"path\"></param>\n    /// <param name=\"options\"></param>\n    /// <returns>success</returns>\n    public Task<bool> PrintToPDFAsync(string path, PrintToPDFOptions options = null)\n    {\n        var tcs = new TaskCompletionSource<bool>();\n\n        BridgeConnector.Socket.Once<bool>(\"webContents-printToPDF-completed\", tcs.SetResult);\n\n        if (options == null)\n        {\n            BridgeConnector.Socket.Emit(\"webContents-printToPDF\", Id, \"\", path);\n        }\n        else\n        {\n            BridgeConnector.Socket.Emit(\"webContents-printToPDF\", Id, options, path);\n        }\n\n        return tcs.Task;\n    }\n\n    /// <summary>\n    /// Evaluates script code in page.\n    /// </summary>\n    /// <param name=\"code\">The code to execute.</param>\n    /// <param name=\"userGesture\">if set to <c>true</c> simulate a user gesture.</param>\n    /// <returns>The result of the executed code.</returns>\n    /// <remarks>\n    /// <para>\n    /// In the browser window some HTML APIs like `requestFullScreen` can only be\n    /// invoked by a gesture from the user. Setting `userGesture` to `true` will remove\n    /// this limitation.\n    /// </para>\n    /// <para>\n    /// Code execution will be suspended until web page stop loading.\n    /// </para>\n    /// </remarks>\n    public Task<T> ExecuteJavaScriptAsync<T>(string code, bool userGesture = false)\n    {\n        var tcs = new TaskCompletionSource<T>();\n\n        BridgeConnector.Socket.Once<T>(\"webContents-executeJavaScript-completed\", tcs.SetResult);\n        BridgeConnector.Socket.Emit(\"webContents-executeJavaScript\", Id, code, userGesture);\n\n        return tcs.Task;\n    }\n\n    /// <summary>\n    /// Is used to get the Url of the loaded page.\n    /// It's usefull if a web-server redirects you and you need to know where it redirects. For instance, It's useful in case of Implicit Authorization.\n    /// </summary>\n    /// <returns>URL of the loaded page</returns>\n    public Task<string> GetUrl()\n    {\n        var tcs = new TaskCompletionSource<string>();\n\n        BridgeConnector.Socket.Once<string>(\"webContents-getUrl\" + Id, tcs.SetResult);\n        BridgeConnector.Socket.Emit(\"webContents-getUrl\", Id);\n\n        return tcs.Task;\n    }\n\n    /// <summary>\n    /// The async method will resolve when the page has finished loading,\n    /// and rejects if the page fails to load.\n    /// \n    /// A noop rejection handler is already attached, which avoids unhandled rejection\n    /// errors.\n    ///\n    /// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g.\n    /// the `http://` or `file://`. If the load should bypass http cache then use the\n    /// `pragma` header to achieve it.\n    /// </summary>\n    /// <param name=\"url\"></param>\n    public Task LoadURLAsync(string url)\n    {\n        return LoadURLAsync(url, new LoadURLOptions());\n    }\n\n    /// <summary>\n    /// The async method will resolve when the page has finished loading,\n    /// and rejects if the page fails to load.\n    /// \n    /// A noop rejection handler is already attached, which avoids unhandled rejection\n    /// errors.\n    ///\n    /// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g.\n    /// the `http://` or `file://`. If the load should bypass http cache then use the\n    /// `pragma` header to achieve it.\n    /// </summary>\n    /// <param name=\"url\"></param>\n    /// <param name=\"options\"></param>\n    public Task LoadURLAsync(string url, LoadURLOptions options)\n    {\n        var tcs = new TaskCompletionSource();\n\n        BridgeConnector.Socket.Once(\"webContents-loadURL-complete\" + Id, () =>\n        {\n            BridgeConnector.Socket.Off(\"webContents-loadURL-error\" + Id);\n            tcs.SetResult();\n        });\n\n        BridgeConnector.Socket.Once<string>(\"webContents-loadURL-error\" + Id, (error) => { tcs.SetException(new InvalidOperationException(error)); });\n\n        BridgeConnector.Socket.Emit(\"webContents-loadURL\", Id, url, options);\n\n        return tcs.Task;\n    }\n\n    /// <summary>\n    /// Inserts CSS into the web page.\n    /// See: https://www.electronjs.org/docs/api/web-contents#contentsinsertcsscss-options\n    /// Works for both BrowserWindows and BrowserViews.\n    /// </summary>\n    /// <param name=\"isBrowserWindow\">Whether the webContents belong to a BrowserWindow or not (the other option is a BrowserView)</param>\n    /// <param name=\"path\">Absolute path to the CSS file location</param>\n    public void InsertCSS(bool isBrowserWindow, string path)\n    {\n        BridgeConnector.Socket.Emit(\"webContents-insertCSS\", Id, isBrowserWindow, path);\n    }\n\n    /// <summary>\n    /// Returns number - The current zoom factor.\n    /// </summary>\n    /// <returns></returns>\n    public Task<double> GetZoomFactorAsync() => InvokeAsync<double>();\n\n    /// <summary>\n    /// Changes the zoom factor to the specified factor.\n    /// Zoom factor is zoom percent divided by 100, so 300% = 3.0.\n    /// The factor must be greater than 0.0.\n    /// </summary>\n    /// <param name=\"factor\"></param>\n    public void SetZoomFactor(double factor)\n    {\n        BridgeConnector.Socket.Emit(\"webContents-setZoomFactor\", Id, factor);\n    }\n\n    /// <summary>\n    /// Returns number - The current zoom level.\n    /// </summary>\n    /// <returns></returns>\n    public Task<int> GetZoomLevelAsync() => InvokeAsync<int>();\n\n    /// <summary>\n    /// Changes the zoom level to the specified level.\n    /// The original size is 0 and each increment above or below represents zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively.\n    /// </summary>\n    /// <param name=\"level\"></param>\n    public void SetZoomLevel(int level)\n    {\n        BridgeConnector.Socket.Emit(\"webContents-setZoomLevel\", Id, level);\n    }\n\n    /// <summary>\n    /// Sets the maximum and minimum pinch-to-zoom level.\n    /// </summary>\n    /// <param name=\"minimumLevel\"></param>\n    /// <param name=\"maximumLevel\"></param>\n    public Task SetVisualZoomLevelLimitsAsync(int minimumLevel, int maximumLevel)\n    {\n        var tcs = new TaskCompletionSource();\n\n        BridgeConnector.Socket.Once(\"webContents-setVisualZoomLevelLimits-completed\", tcs.SetResult);\n        BridgeConnector.Socket.Emit(\"webContents-setVisualZoomLevelLimits\", Id, minimumLevel, maximumLevel);\n\n        return tcs.Task;\n    }\n\n    /// <summary>\n    /// Returns boolean - Whether this page has been muted.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsAudioMutedAsync() => InvokeAsync<bool>();\n\n    /// <summary>\n    /// Returns boolean - Whether audio is currently playing.\n    /// </summary>\n    /// <returns></returns>\n    public Task<bool> IsCurrentlyAudibleAsync() => InvokeAsync<bool>();\n\n    /// <summary>\n    /// Mute the audio on the current web page.\n    /// </summary>\n    /// <param name=\"muted\"></param>\n    public void SetAudioMuted(bool muted)\n    {\n        BridgeConnector.Socket.Emit(\"webContents-setAudioMuted\", Id, muted);\n    }\n\n    /// <summary>\n    /// Returns string - The user agent for this web page.\n    /// </summary>\n    /// <returns></returns>\n    public Task<string> GetUserAgentAsync() => InvokeAsyncWithTimeout<string>(3.seconds());\n\n    /// <summary>\n    /// Overrides the user agent for this web page.\n    /// </summary>\n    /// <param name=\"userAgent\"></param>\n    public void SetUserAgent(string userAgent)\n    {\n        BridgeConnector.Socket.Emit(\"webContents-setUserAgent\", Id, userAgent);\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/WebRequest.cs",
    "content": "using ElectronNET.API.Serialization;\nusing System;\nusing System.Text.Json;\n\nnamespace ElectronNET.API.Entities\n{\n    public class OnBeforeRequestDetails\n    {\n        public int Id { get; set; }\n        public string Url { get; set; }\n        public string Method { get; set; }\n\n        public int? WebContentsId { get; set; }\n        // Ensure all necessary properties are included as per Electron documentation\n    }\n\n    public class WebRequestFilter\n    {\n        public string[] Urls { get; set; }\n    }\n\n    public class WebRequest\n    {\n        public int Id { get; private set; }\n\n        internal WebRequest(int id)\n        {\n            Id = id;\n        }\n\n        private event Action<OnBeforeRequestDetails, Action<object>> _onBeforeRequest;\n\n        public void OnBeforeRequest(WebRequestFilter filter, Action<OnBeforeRequestDetails, Action<object>> listener)\n        {\n            if (_onBeforeRequest == null)\n            {\n                BridgeConnector.Socket.On<JsonElement>($\"webContents-session-webRequest-onBeforeRequest{Id}\",\n                    (args) =>\n                    {\n                        //// var details0 = args[0].Deserialize<OnBeforeRequestDetails>(ElectronNET.ElectronJson.Options);\n                        var details = args.Deserialize<OnBeforeRequestDetails>(ElectronJson.Options);\n                        var callback = (Action<object>)((response) => { BridgeConnector.Socket.Emit($\"webContents-session-webRequest-onBeforeRequest-response{Id}\", response); });\n\n                        _onBeforeRequest?.Invoke(details, callback);\n                    });\n\n                BridgeConnector.Socket.Emit(\"register-webContents-session-webRequest-onBeforeRequest\", Id, filter);\n            }\n\n            _onBeforeRequest += listener;\n        }\n\n        public void RemoveListener(Action<OnBeforeRequestDetails, Action<object>> listener)\n        {\n            _onBeforeRequest -= listener;\n            if (_onBeforeRequest == null)\n            {\n                BridgeConnector.Socket.Off($\"webContents-session-webRequest-onBeforeRequest{Id}\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/WindowManager.cs",
    "content": "using ElectronNET.API.Entities;\nusing ElectronNET.API.Serialization;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.API\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public sealed class WindowManager\n    {\n        private static WindowManager _windowManager;\n        private static readonly object SyncRoot = new();\n\n        internal WindowManager()\n        {\n        }\n\n        internal static WindowManager Instance\n        {\n            get\n            {\n                if (_windowManager == null)\n                {\n                    lock (SyncRoot)\n                    {\n                        if (_windowManager == null)\n                        {\n                            _windowManager = new WindowManager();\n                        }\n                    }\n                }\n\n                return _windowManager;\n            }\n        }\n\n        /// <summary>\n        /// Quit when all windows are closed. (Default is true)\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [quit window all closed]; otherwise, <c>false</c>.\n        /// </value>\n        public bool IsQuitOnWindowAllClosed\n        {\n            get => _isQuitOnWindowAllClosed;\n            set\n            {\n                BridgeConnector.Socket.Emit(\"quit-app-window-all-closed\", value);\n                _isQuitOnWindowAllClosed = value;\n            }\n        }\n\n        private bool _isQuitOnWindowAllClosed = true;\n\n        /// <summary>\n        /// Gets the browser windows.\n        /// </summary>\n        /// <value>\n        /// The browser windows.\n        /// </value>\n        public IReadOnlyCollection<BrowserWindow> BrowserWindows => _browserWindows.AsReadOnly();\n\n        private readonly List<BrowserWindow> _browserWindows = new();\n\n        /// <summary>\n        /// Gets the browser views.\n        /// </summary>\n        /// <value>\n        /// The browser view.\n        /// </value>\n        public IReadOnlyCollection<BrowserView> BrowserViews => _browserViews.AsReadOnly();\n\n        private readonly List<BrowserView> _browserViews = new();\n\n        /// <summary>\n        /// Creates the window asynchronous.\n        /// </summary>\n        /// <param name=\"loadUrl\">The load URL.</param>\n        /// <returns></returns>\n        public async Task<BrowserWindow> CreateWindowAsync(string loadUrl = \"http://localhost\")\n        {\n            return await this.CreateWindowAsync(new BrowserWindowOptions(), loadUrl).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Creates the window asynchronous.\n        /// </summary>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"loadUrl\">The load URL.</param>\n        /// <returns></returns>\n        public async Task<BrowserWindow> CreateWindowAsync(BrowserWindowOptions options, string loadUrl = \"http://localhost\")\n        {\n            var tcs = new TaskCompletionSource<BrowserWindow>();\n\n            BridgeConnector.Socket.Once<int>(\"BrowserWindowCreated\", (id) =>\n            {\n                var browserWindow = new BrowserWindow(id);\n                _browserWindows.Add(browserWindow);\n\n                tcs.SetResult(browserWindow);\n            });\n\n            BridgeConnector.Socket.Once<int[]>(\"BrowserWindowClosed\", (ids) =>\n            {\n                for (int index = 0; index < _browserWindows.Count; index++)\n                {\n                    if (!ids.Contains(_browserWindows[index].Id))\n                    {\n                        _browserWindows.RemoveAt(index);\n                    }\n                }\n            });\n\n            if (loadUrl.Equals(\"http://localhost\", StringComparison.OrdinalIgnoreCase) && ElectronNetRuntime.AspNetWebPort.HasValue)\n            {\n                loadUrl = $\"{loadUrl}:{ElectronNetRuntime.AspNetWebPort}\";\n            }\n\n            // Workaround Windows 10 / Electron Bug\n            // https://github.com/electron/electron/issues/4045\n            if (IsWindows10())\n            {\n                options.Width += 14;\n                options.Height += 7;\n            }\n\n            if (!options.X.HasValue && !options.Y.HasValue)\n            {\n                await BridgeConnector.Socket.Emit(\"createBrowserWindow\", options, loadUrl).ConfigureAwait(false);\n            }\n            else\n            {\n                // Workaround Windows 10 / Electron Bug\n                // https://github.com/electron/electron/issues/4045\n                if (IsWindows10())\n                {\n                    options.X -= 7;\n                }\n\n                await BridgeConnector.Socket.Emit(\"createBrowserWindow\", options, loadUrl).ConfigureAwait(false);\n            }\n\n            return await tcs.Task.ConfigureAwait(false);\n        }\n\n        private bool IsWindows10()\n        {\n            return RuntimeInformation.OSDescription.Contains(\"Windows 10\");\n        }\n\n        /// <summary>\n        /// A BrowserView can be used to embed additional web content into a BrowserWindow.\n        /// It is like a child window, except that it is positioned relative to its owning window.\n        /// It is meant to be an alternative to the webview tag.\n        /// </summary>\n        /// <returns></returns>\n        public Task<BrowserView> CreateBrowserViewAsync()\n        {\n            return CreateBrowserViewAsync(new BrowserViewConstructorOptions());\n        }\n\n        /// <summary>\n        /// A BrowserView can be used to embed additional web content into a BrowserWindow.\n        /// It is like a child window, except that it is positioned relative to its owning window.\n        /// It is meant to be an alternative to the webview tag.\n        /// </summary>\n        /// <param name=\"options\"></param>\n        /// <returns></returns>\n        public async Task<BrowserView> CreateBrowserViewAsync(BrowserViewConstructorOptions options)\n        {\n            var tcs = new TaskCompletionSource<BrowserView>();\n\n            BridgeConnector.Socket.Once<int>(\"BrowserViewCreated\", (id) =>\n            {\n                BrowserView browserView = new(id);\n\n                _browserViews.Add(browserView);\n\n                tcs.SetResult(browserView);\n            });\n\n            await BridgeConnector.Socket.Emit(\"createBrowserView\", options).ConfigureAwait(false);\n\n            return await tcs.Task.ConfigureAwait(false);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/API/web-request.md",
    "content": "﻿## Class: WebRequest\n\n> Intercept and modify the contents of a request at various stages of its lifetime.\n\nProcess: [Main](../glossary.md#main-process)<br />\n_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._\n\nInstances of the `WebRequest` class are accessed by using the `webRequest`\nproperty of a `Session`.\n\nThe methods of `WebRequest` accept an optional `filter` and a `listener`. The\n`listener` will be called with `listener(details)` when the API's event has\nhappened. The `details` object describes the request.\n\n⚠️ Only the last attached `listener` will be used. Passing `null` as `listener` will unsubscribe from the event.\n\nThe `filter` object has a `urls` property which is an Array of URL\npatterns that will be used to filter out the requests that do not match the URL\npatterns. If the `filter` is omitted then all requests will be matched.\n\nFor certain events the `listener` is passed with a `callback`, which should be\ncalled with a `response` object when `listener` has done its work.\n\nAn example of adding `User-Agent` header for requests:\n\n```js\nconst { session } = require('electron')\n\n// Modify the user agent for all requests to the following urls.\nconst filter = {\n  urls: ['https://*.github.com/*', '*://electron.github.io/*']\n}\n\nsession.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => {\n  details.requestHeaders['User-Agent'] = 'MyAgent'\n  callback({ requestHeaders: details.requestHeaders })\n})\n```\n\n### Instance Methods\n\nThe following methods are available on instances of `WebRequest`:\n\n#### `webRequest.onBeforeRequest([filter, ]listener)`\n\n* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional)\n* `listener` Function | null\n  * `details` Object\n    * `id` Integer\n    * `url` string\n    * `method` string\n    * `webContentsId` Integer (optional)\n    * `webContents` WebContents (optional)\n    * `frame` WebFrameMain (optional)\n    * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.\n    * `referrer` string\n    * `timestamp` Double\n    * `uploadData` [UploadData[]](structures/upload-data.md)\n  * `callback` Function\n    * `response` Object\n      * `cancel` boolean (optional)\n      * `redirectURL` string (optional) - The original request is prevented from\n        being sent or completed and is instead redirected to the given URL.\n\nThe `listener` will be called with `listener(details, callback)` when a request\nis about to occur.\n\nThe `uploadData` is an array of `UploadData` objects.\n\nThe `callback` has to be called with an `response` object.\n\nSome examples of valid `urls`:\n\n```js\n'http://foo:1234/'\n'http://foo.com/'\n'http://foo:1234/bar'\n'*://*/*'\n'*://example.com/*'\n'*://example.com/foo/*'\n'http://*.foo:1234/'\n'file://foo:1234/bar'\n'http://foo:*/'\n'*://www.foo.com/'\n```\n\n#### `webRequest.onBeforeSendHeaders([filter, ]listener)`\n\n* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional)\n* `listener` Function | null\n  * `details` Object\n    * `id` Integer\n    * `url` string\n    * `method` string\n    * `webContentsId` Integer (optional)\n    * `webContents` WebContents (optional)\n    * `frame` WebFrameMain (optional)\n    * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.\n    * `referrer` string\n    * `timestamp` Double\n    * `uploadData` [UploadData[]](structures/upload-data.md) (optional)\n    * `requestHeaders` Record<string, string>\n  * `callback` Function\n    * `beforeSendResponse` Object\n      * `cancel` boolean (optional)\n      * `requestHeaders` Record<string, string | string[]> (optional) - When provided, request will be made\n  with these headers.\n\nThe `listener` will be called with `listener(details, callback)` before sending\nan HTTP request, once the request headers are available. This may occur after a\nTCP connection is made to the server, but before any http data is sent.\n\nThe `callback` has to be called with a `response` object.\n\n#### `webRequest.onSendHeaders([filter, ]listener)`\n\n* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional)\n* `listener` Function | null\n  * `details` Object\n    * `id` Integer\n    * `url` string\n    * `method` string\n    * `webContentsId` Integer (optional)\n    * `webContents` WebContents (optional)\n    * `frame` WebFrameMain (optional)\n    * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.\n    * `referrer` string\n    * `timestamp` Double\n    * `requestHeaders` Record<string, string>\n\nThe `listener` will be called with `listener(details)` just before a request is\ngoing to be sent to the server, modifications of previous `onBeforeSendHeaders`\nresponse are visible by the time this listener is fired.\n\n#### `webRequest.onHeadersReceived([filter, ]listener)`\n\n* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional)\n* `listener` Function | null\n  * `details` Object\n    * `id` Integer\n    * `url` string\n    * `method` string\n    * `webContentsId` Integer (optional)\n    * `webContents` WebContents (optional)\n    * `frame` WebFrameMain (optional)\n    * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.\n    * `referrer` string\n    * `timestamp` Double\n    * `statusLine` string\n    * `statusCode` Integer\n    * `responseHeaders` Record<string, string[]> (optional)\n  * `callback` Function\n    * `headersReceivedResponse` Object\n      * `cancel` boolean (optional)\n      * `responseHeaders` Record<string, string | string[]> (optional) - When provided, the server is assumed\n        to have responded with these headers.\n      * `statusLine` string (optional) - Should be provided when overriding\n        `responseHeaders` to change header status otherwise original response\n        header's status will be used.\n\nThe `listener` will be called with `listener(details, callback)` when HTTP\nresponse headers of a request have been received.\n\nThe `callback` has to be called with a `response` object.\n\n#### `webRequest.onResponseStarted([filter, ]listener)`\n\n* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional)\n* `listener` Function | null\n  * `details` Object\n    * `id` Integer\n    * `url` string\n    * `method` string\n    * `webContentsId` Integer (optional)\n    * `webContents` WebContents (optional)\n    * `frame` WebFrameMain (optional)\n    * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.\n    * `referrer` string\n    * `timestamp` Double\n    * `responseHeaders` Record<string, string[]> (optional)\n    * `fromCache` boolean - Indicates whether the response was fetched from disk\n      cache.\n    * `statusCode` Integer\n    * `statusLine` string\n\nThe `listener` will be called with `listener(details)` when first byte of the\nresponse body is received. For HTTP requests, this means that the status line\nand response headers are available.\n\n#### `webRequest.onBeforeRedirect([filter, ]listener)`\n\n* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional)\n* `listener` Function | null\n  * `details` Object\n    * `id` Integer\n    * `url` string\n    * `method` string\n    * `webContentsId` Integer (optional)\n    * `webContents` WebContents (optional)\n    * `frame` WebFrameMain (optional)\n    * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.\n    * `referrer` string\n    * `timestamp` Double\n    * `redirectURL` string\n    * `statusCode` Integer\n    * `statusLine` string\n    * `ip` string (optional) - The server IP address that the request was\n      actually sent to.\n    * `fromCache` boolean\n    * `responseHeaders` Record<string, string[]> (optional)\n\nThe `listener` will be called with `listener(details)` when a server initiated\nredirect is about to occur.\n\n#### `webRequest.onCompleted([filter, ]listener)`\n\n* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional)\n* `listener` Function | null\n  * `details` Object\n    * `id` Integer\n    * `url` string\n    * `method` string\n    * `webContentsId` Integer (optional)\n    * `webContents` WebContents (optional)\n    * `frame` WebFrameMain (optional)\n    * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.\n    * `referrer` string\n    * `timestamp` Double\n    * `responseHeaders` Record<string, string[]> (optional)\n    * `fromCache` boolean\n    * `statusCode` Integer\n    * `statusLine` string\n    * `error` string\n\nThe `listener` will be called with `listener(details)` when a request is\ncompleted.\n\n#### `webRequest.onErrorOccurred([filter, ]listener)`\n\n* `filter` [WebRequestFilter](structures/web-request-filter.md) (optional)\n* `listener` Function | null\n  * `details` Object\n    * `id` Integer\n    * `url` string\n    * `method` string\n    * `webContentsId` Integer (optional)\n    * `webContents` WebContents (optional)\n    * `frame` WebFrameMain (optional)\n    * `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.\n    * `referrer` string\n    * `timestamp` Double\n    * `fromCache` boolean\n    * `error` string - The error description.\n\nThe `listener` will be called with `listener(details)` when an error occurs."
  },
  {
    "path": "src/ElectronNET.API/Bridge/BridgeConnector.cs",
    "content": "﻿#pragma warning disable IDE0130 // Namespace does not match folder structure\n// ReSharper disable once CheckNamespace\nnamespace ElectronNET.API\n{\n    internal static class BridgeConnector\n    {\n        public static SocketIoFacade Socket\n        {\n            get\n            {\n                return ElectronNetRuntime.GetSocket();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Bridge/Events.cs",
    "content": "﻿#pragma warning disable IDE0130 // Namespace does not match folder structure\n// ReSharper disable once CheckNamespace\nnamespace ElectronNET.API\n{\n    using System;\n    using System.Globalization;\n    using System.Threading.Tasks;\n\n    /// <summary>\n    /// Generic Event Consumers for Electron Modules\n    /// </summary>\n    internal class Events\n    {\n        private static Events _events;\n        private static readonly object SyncRoot = new();\n        private readonly TextInfo _textInfo = new CultureInfo(\"en-US\", false).TextInfo;\n\n        private Events()\n        {\n        }\n\n        public static Events Instance\n        {\n            get\n            {\n                if (_events == null)\n                {\n                    lock (SyncRoot)\n                    {\n                        if (_events == null)\n                        {\n                            _events = new Events();\n                        }\n                    }\n                }\n\n                return _events;\n            }\n        }\n\n        /// <summary>\n        /// Subscribe to an unmapped electron event.\n        /// </summary>\n        /// <param name=\"moduleName\">The name of the module, e.g. app, dock, etc...</param>\n        /// <param name=\"eventName\">The name of the event</param>\n        /// <param name=\"action\">The event handler</param>\n        public async Task On(string moduleName, string eventName, Action action)\n        {\n            var listener = $\"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed\";\n            var subscriber = $\"register-{moduleName}-on-event\";\n\n            BridgeConnector.Socket.On(listener, action);\n            await BridgeConnector.Socket.Emit(subscriber, eventName, listener).ConfigureAwait(false);\n        }\n\n\n        /// <summary>\n        /// Subscribe to an unmapped electron event.\n        /// </summary>\n        /// <param name=\"moduleName\">The name of the module, e.g. app, dock, etc...</param>\n        /// <param name=\"eventName\">The name of the event</param>\n        /// <param name=\"action\">The event handler</param>\n        public async Task On<T>(string moduleName, string eventName, Action<T> action)\n        {\n            var listener = $\"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed\";\n            var subscriber = $\"register-{moduleName}-on-event\";\n\n            BridgeConnector.Socket.On(listener, action);\n            await BridgeConnector.Socket.Emit(subscriber, eventName, listener).ConfigureAwait(false);\n        }\n\n        /// <summary>Subscribe to an unmapped electron event.</summary>\n        /// <param name=\"moduleName\">The name of the module, e.g. app, dock, etc...</param>\n        /// <param name=\"eventName\">The name of the event</param>\n        /// <param name=\"action\">The action.</param>\n        public async Task Once(string moduleName, string eventName, Action action)\n        {\n            var listener = $\"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed\";\n            var subscriber = $\"register-{moduleName}-once-event\";\n            BridgeConnector.Socket.Once(listener, action);\n            await BridgeConnector.Socket.Emit(subscriber, eventName, listener).ConfigureAwait(false);\n        }\n\n\n        /// <summary>\n        /// Subscribe to an unmapped electron event.\n        /// </summary>\n        /// <param name=\"moduleName\">The name of the module, e.g. app, dock, etc...</param>\n        /// <param name=\"eventName\">The name of the event</param>\n        /// <param name=\"action\">The event handler</param>\n        public async Task Once<T>(string moduleName, string eventName, Action<T> action)\n        {\n            var listener = $\"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed\";\n            var subscriber = $\"register-{moduleName}-once-event\";\n            BridgeConnector.Socket.Once(listener, action);\n            await BridgeConnector.Socket.Emit(subscriber, eventName, listener).ConfigureAwait(false);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Bridge/SocketIOFacade.cs",
    "content": "﻿#pragma warning disable IDE0130 // Namespace does not match folder structure\n// ReSharper disable once CheckNamespace\nnamespace ElectronNET.API;\n\nusing System;\nusing System.Threading.Tasks;\nusing ElectronNET.API.Serialization;\nusing SocketIO.Serializer.SystemTextJson;\nusing SocketIO = SocketIOClient.SocketIO;\n\ninternal class SocketIoFacade : IDisposable\n{\n    private readonly SocketIO _socket;\n    private readonly object _lockObj = new object();\n    private bool _isDisposed;\n\n    public SocketIoFacade(string uri)\n    {\n        _socket = new SocketIO(uri);\n        _socket.Serializer = new SystemTextJsonSerializer(ElectronJson.Options);\n        // Use default System.Text.Json serializer from SocketIOClient.\n        // Outgoing args are normalized to camelCase via SerializeArg in Emit.\n    }\n\n    public event EventHandler BridgeDisconnected;\n\n    public event EventHandler BridgeConnected;\n\n    public void Connect()\n    {\n        this.CheckDisposed();\n\n        _socket.OnError += (sender, e) => { Console.WriteLine($\"BridgeConnector Error: {sender} {e}\"); };\n\n        _socket.OnConnected += (_, _) =>\n        {\n            Console.WriteLine(\"BridgeConnector connected!\");\n            this.BridgeConnected?.Invoke(this, EventArgs.Empty);\n        };\n\n        _socket.OnDisconnected += (_, _) =>\n        {\n            Console.WriteLine(\"BridgeConnector disconnected!\");\n            this.BridgeDisconnected?.Invoke(this, EventArgs.Empty);\n        };\n\n        _socket.ConnectAsync().GetAwaiter().GetResult();\n    }\n\n    public void On(string eventName, Action action)\n    {\n        this.CheckDisposed();\n\n        lock (_lockObj)\n        {\n            _socket.On(eventName, _ => { Task.Run(action); });\n        }\n    }\n\n    public void On<T>(string eventName, Action<T> action)\n    {\n        this.CheckDisposed();\n\n        lock (_lockObj)\n        {\n            _socket.On(eventName, response =>\n            {\n                var value = response.GetValue<T>();\n                Task.Run(() => action(value));\n            });\n        }\n    }\n\n    public void Once(string eventName, Action action)\n    {\n        this.CheckDisposed();\n\n        lock (_lockObj)\n        {\n            _socket.On(eventName, _ =>\n            {\n                this.Off(eventName);\n                Task.Run(action);\n            });\n        }\n    }\n\n    public void Once<T>(string eventName, Action<T> action)\n    {\n        this.CheckDisposed();\n\n        lock (_lockObj)\n        {\n            _socket.On(eventName, (socketIoResponse) =>\n            {\n                this.Off(eventName);\n                Task.Run(() => action(socketIoResponse.GetValue<T>()));\n            });\n        }\n    }\n\n    public void Off(string eventName)\n    {\n        if (_isDisposed)\n        {\n            return;\n        }\n\n        lock (_lockObj)\n        {\n            _socket.Off(eventName);\n        }\n    }\n\n    public async Task Emit(string eventName, params object[] args)\n    {\n        if (!_isDisposed)\n        {\n            await _socket.EmitAsync(eventName, args).ConfigureAwait(false);\n        }\n    }\n\n    /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>\n    public void Dispose()\n    {\n        Dispose(true);\n        GC.SuppressFinalize(this);\n    }\n\n    protected virtual void Dispose(bool disposing)\n    {\n        if (disposing)\n        {\n            _isDisposed = true;\n            _socket.Dispose();\n        }\n    }\n\n    private void CheckDisposed()\n    {\n        if (this._isDisposed)\n        {\n            throw new ObjectDisposedException(nameof(SocketIoFacade));\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Common/Extensions.cs",
    "content": "﻿using System.Globalization;\nusing System.Text.RegularExpressions;\nusing System;\nusing ElectronNET.Runtime.Data;\nusing ElectronNET.Runtime.Services;\n\nnamespace ElectronNET.Common\n{\n    internal static class Extensions\n    {\n        public static bool IsUnpackaged(this StartupMethod method)\n        {\n            switch (method)\n            {\n                case StartupMethod.UnpackedElectronFirst:\n                case StartupMethod.UnpackedDotnetFirst:\n                    return true;\n                default:\n                    return false;\n            }\n        }\n\n        public static string LowerFirst(this string str)\n        {\n            if (string.IsNullOrWhiteSpace(str))\n            {\n                return str;\n            }\n\n            if (str.Length == 1)\n            {\n                return str.ToLower();\n            }\n\n            return char.ToLower(str[0]) + str.Substring(1);\n        }\n\n        public static string StripAsync(this string str)\n        {\n            if (string.IsNullOrWhiteSpace(str))\n            {\n                return str;\n            }\n\n            var pos = str.LastIndexOf(\"Async\", StringComparison.Ordinal);\n\n            if (pos > 0)\n            {\n                return str.Substring(0, pos);\n            }\n\n            return str;\n        }\n\n        public static string StripOn(this string str)\n        {\n            if (string.IsNullOrWhiteSpace(str) || !str.StartsWith(\"On\", StringComparison.Ordinal))\n            {\n                return str;\n            }\n\n            return str.Substring(2);\n        }\n\n        public static string ToDashedEventName(this string str)\n        {\n            return string.Join(\"-\", Regex.Split(str.StripOn(), \"(?<!^)(?=[A-Z])\")).ToLower(CultureInfo.InvariantCulture);\n        }\n\n        public static string ToCamelCaseEventName(this string str)\n        {\n            return str.StripOn().LowerFirst();\n        }\n\n        public static bool IsReady(this LifetimeServiceBase service)\n        {\n            return service != null && service.State == LifetimeState.Ready;\n        }\n\n        public static bool IsNotStopped(this LifetimeServiceBase service)\n        {\n            return service != null && service.State != LifetimeState.Stopped;\n        }\n\n        public static bool IsNullOrStopped(this LifetimeServiceBase service)\n        {\n            return service == null || service.State == LifetimeState.Stopped;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Common/ProcessRunner.cs",
    "content": "﻿namespace ElectronNET.Common\n{\n    using System;\n    using System.Diagnostics;\n    using System.Diagnostics.CodeAnalysis;\n    using System.Text;\n    using System.Threading;\n    using System.Threading.Tasks;\n\n    /// <summary>\n    /// Class encapsulating out-of-process execution of console applications.\n    /// </summary>\n    /// <remarks>\n    ///     Why this class?\n    ///     Probably everybody who has tried to use System.Diagnotics.Process cross-platform and with reading\n    ///     stderr and stdout will know that it is a pretty quirky API.\n    ///     The code below may look weird, even non-sensical, but it works 100% reliable with all .net frameworks\n    ///     and .net versions and on every platform where .net runs. This is just the innermost core, that's why\n    ///     there are many dead ends, but it has all the crucial parts.\n    /// </remarks>\n    /// <seealso cref=\"IDisposable\" />\n    [SuppressMessage(\"ReSharper\", \"SuspiciousLockOverSynchronizationPrimitive\")]\n    public class ProcessRunner : IDisposable\n    {\n        private volatile Process process;\n        private readonly StringBuilder stdOut = new StringBuilder(4 * 1024);\n        private readonly StringBuilder stdErr = new StringBuilder(4 * 1024);\n\n        private volatile ManualResetEvent stdOutEvent;\n        private volatile ManualResetEvent stdErrEvent;\n        private volatile Stopwatch stopwatch;\n\n        /// <summary>Initializes a new instance of the <see cref=\"ProcessRunner\" /> class.</summary>\n        /// <param name=\"name\">A name identifying the process to execute.</param>\n        public ProcessRunner(string name)\n        {\n            this.Name = name;\n        }\n\n        public event EventHandler<EventArgs> ProcessExited;\n\n        public bool IsDisposed { get; private set; }\n\n        private Process Process\n        {\n            get\n            {\n                return this.process;\n            }\n        }\n\n        public bool IsRunning\n        {\n            get\n            {\n                var proc = this.process;\n                if (proc != null)\n                {\n                    try\n                    {\n                        return !proc.HasExited;\n                    }\n                    catch\n                    {\n                        return false;\n                    }\n                }\n\n                return false;\n            }\n        }\n\n        /// <summary>Gets the name identifying the process.</summary>\n        /// <value>The name.</value>\n        public string Name { get; }\n\n        public string CommandLine { get; private set; }\n\n        public string ExecutableFileName { get; private set; }\n\n        public string WorkingFolder { get; private set; }\n\n        public bool RecordStandardOutput { get; set; }\n\n        public bool RecordStandardError { get; set; }\n\n        public string StandardOutput\n        {\n            get\n            {\n                lock (this.stdOut)\n                {\n                    return this.stdOut.ToString();\n                }\n            }\n        }\n\n        public string StandardError\n        {\n            get\n            {\n                lock (this.stdErr)\n                {\n                    return this.stdErr.ToString();\n                }\n            }\n        }\n\n        public int? LastExitCode { get; private set; }\n\n        public bool Run(string exeFileName, string commandLineArgs, string workingDirectory)\n        {\n            this.CommandLine = commandLineArgs;\n            this.WorkingFolder = workingDirectory;\n            this.ExecutableFileName = exeFileName;\n\n            var startInfo = new RunnerParams(exeFileName)\n            {\n                Arguments = commandLineArgs,\n                UseShellExecute = false,\n                RedirectStandardOutput = true,\n                RedirectStandardError = true,\n                RedirectStandardInput = true,\n                ErrorDialog = false,\n                CreateNoWindow = true,\n                WorkingDirectory = workingDirectory\n            };\n\n            return this.Run(startInfo);\n        }\n\n        protected bool Run(RunnerParams runnerParams)\n        {\n            if (this.IsDisposed)\n            {\n                throw new ObjectDisposedException(this.GetType().ToString());\n            }\n\n            this.Close();\n\n            this.LastExitCode = null;\n\n            lock (this.stdOut)\n            {\n                this.stdOut.Clear();\n            }\n\n            lock (this.stdErr)\n            {\n                this.stdErr.Clear();\n            }\n\n            this.stdOutEvent = new ManualResetEvent(false);\n            this.stdErrEvent = new ManualResetEvent(false);\n\n            if (!this.OnBeforeStartProcessCore(runnerParams))\n            {\n                return false;\n            }\n\n            var startInfo = new ProcessStartInfo(runnerParams.FileName)\n            {\n                Arguments = runnerParams.Arguments,\n                UseShellExecute = runnerParams.UseShellExecute,\n                RedirectStandardOutput = runnerParams.RedirectStandardOutput,\n                RedirectStandardError = runnerParams.RedirectStandardError,\n                RedirectStandardInput = runnerParams.RedirectStandardInput,\n                ErrorDialog = runnerParams.ErrorDialog,\n                CreateNoWindow = runnerParams.CreateNoWindow,\n                WorkingDirectory = runnerParams.WorkingDirectory\n            };\n\n            foreach (var variableSetting in runnerParams.EnvironmentVariables)\n            {\n                startInfo.EnvironmentVariables[variableSetting.Key] = variableSetting.Value;\n            }\n\n            var proc = new Process { StartInfo = startInfo };\n\n            proc.EnableRaisingEvents = true;\n\n            this.RegisterProcessEvents(proc);\n\n            this.process = proc;\n\n            try\n            {\n                this.process.Start();\n                this.stopwatch = Stopwatch.StartNew();\n                this.process.BeginOutputReadLine();\n                this.process.BeginErrorReadLine();\n                this.process.Refresh();\n                this.OnProcessStartedCore();\n            }\n            catch (Exception ex)\n            {\n                this.OnProcessErrorCore(ex);\n                this.Close();\n                throw;\n            }\n\n            return true;\n        }\n\n        public async Task<bool> WriteAsync(string data)\n        {\n            var proc = this.Process;\n            if (proc != null && !proc.HasExited)\n            {\n                try\n                {\n                    await proc.StandardInput.WriteAsync(data).ConfigureAwait(false);\n                    return true;\n                }\n                catch (Exception ex)\n                {\n                    Console.WriteLine(\"{0}.{1}: {2}\", ex, nameof(ProcessRunner), nameof(this.WriteAsync));\n                }\n            }\n\n            return false;\n        }\n\n        public bool WaitForExit()\n        {\n            var proc = this.process;\n\n            if (proc == null)\n            {\n                return true;\n            }\n\n            try\n            {\n                // Wait for process and all I/O to finish.\n                proc.WaitForExit();\n                return true;\n            }\n            catch (Exception ex)\n            {\n                this.OnProcessErrorCore(ex);\n                return false;\n            }\n        }\n\n        /// <summary>Sychronously waits for the specified amount and ends the process afterwards.</summary>\n        /// <param name=\"timeoutMs\">The timeout ms.</param>\n        /// <remarks>This method allows for a clean exit, since it also waits until the StandardOutput and\n        /// StandardError pipes are processed to the end.</remarks>\n        /// <returns>true, if the process has exited gracefully; false otherwise.</returns>\n        public bool WaitAndKill(int timeoutMs)\n        {\n            var proc = this.process;\n\n            if (proc == null)\n            {\n                return true;\n            }\n\n            try\n            {\n                if (timeoutMs <= 0)\n                {\n                    throw new ArgumentException(\"Argument must be greater then 0\", nameof(timeoutMs));\n                }\n\n                // Timed waiting. We need to wait for I/O ourselves.\n                if (!proc.WaitForExit(timeoutMs))\n                {\n                    this.Cancel();\n                }\n\n                // Wait for the I/O to finish.\n                var waitMs = (int)(timeoutMs - this.stopwatch.ElapsedMilliseconds);\n                waitMs = Math.Max(waitMs, 10);\n                this.stdOutEvent?.WaitOne(waitMs);\n\n                waitMs = (int)(timeoutMs - this.stopwatch.ElapsedMilliseconds);\n                waitMs = Math.Max(waitMs, 10);\n                return this.stdErrEvent?.WaitOne(waitMs) ?? false;\n            }\n            finally\n            {\n                // Cleanup.\n                this.Cancel();\n            }\n        }\n\n        /// <summary>Asynchronously waits for the specified amount and ends the process afterwards.</summary>\n        /// <param name=\"timeoutMs\">The timeout ms.</param>\n        /// <remarks>Tjhis method performs the wait operation on a threadpool thread.\n        /// Only recommended for short timeouts and situations where a synchronous call is undesired.</remarks>\n        /// <returns>true, if the process has exited gracefully; false otherwise.</returns>\n        public Task<bool> WaitAndKillAsync(int timeoutMs)\n        {\n            var task = Task.Run(() => this.WaitAndKill(timeoutMs));\n            return task;\n        }\n\n        /// <summary>Waits asynchronously for the process to exit.</summary>\n        /// <param name=\"timeoutMs\">The timeout ms.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>true, if the process has exited, false if the process is still running.</returns>\n        /// <remarks>\n        /// This methods waits until the process has existed or the\n        /// <paramref name=\"timeoutMs\" /> has elapsed.\n        /// This method does not end the process itself.\n        /// </remarks>\n        public Task<bool> WaitForExitAsync(int timeoutMs, CancellationToken cancellationToken = default)\n        {\n            timeoutMs = Math.Max(0, timeoutMs);\n\n            var timeoutSource = new CancellationTokenSource(timeoutMs);\n            var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, cancellationToken);\n\n            return this.WaitForExitAsync(linkedSource.Token);\n        }\n\n        /// <summary>Waits asynchronously for the process to exit.</summary>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <remarks>This methods waits until the process has existed or the\n        /// <paramref name=\"cancellationToken\"/> has been triggered.\n        /// This method does not end the process itself.</remarks>\n        /// <returns>true, if the process has exited, false if the process is still running.</returns>\n        public async Task<bool> WaitForExitAsync(CancellationToken cancellationToken = default)\n        {\n            var proc = this.process;\n\n            if (proc == null)\n            {\n                return true;\n            }\n\n            var tcs = new TaskCompletionSource<bool>();\n\n            // Use local function instead of a lambda to allow proper deregistration of the event\n            void ProcessExited(object sender, EventArgs e)\n            {\n                tcs.TrySetResult(true);\n            }\n\n            try\n            {\n                proc.EnableRaisingEvents = true;\n                proc.Exited += ProcessExited;\n\n                if (proc.HasExited)\n                {\n                    return true;\n                }\n\n                using (cancellationToken.Register(() => tcs.TrySetResult(false)))\n                {\n                    return await tcs.Task.ConfigureAwait(false);\n                }\n            }\n            finally\n            {\n                proc.Exited -= ProcessExited;\n            }\n        }\n\n        public void Cancel()\n        {\n            var proc = this.process;\n\n            if (proc != null)\n            {\n                try\n                {\n                    // Invalidate cached data to requery.\n                    proc.Refresh();\n\n                    // We need to do this in case of a non-UI proc\n                    // or one to be forced to cancel.\n                    if (!proc.HasExited)\n                    {\n                        // Cancel all pending IO ops.\n                        proc.CancelErrorRead();\n                        proc.CancelOutputRead();\n                    }\n\n                    if (!proc.HasExited)\n                    {\n                        proc.Kill();\n                    }\n                }\n                catch\n                {\n                    // Kill will throw when/if the process has already exited.\n                }\n            }\n\n            var outEvent = this.stdOutEvent;\n            this.stdOutEvent = null;\n            if (outEvent != null)\n            {\n                lock (outEvent)\n                {\n                    outEvent.Close();\n                    outEvent.Dispose();\n                }\n            }\n\n            var errEvent = this.stdErrEvent;\n            this.stdErrEvent = null;\n            if (errEvent != null)\n            {\n                lock (errEvent)\n                {\n                    errEvent.Close();\n                    errEvent.Dispose();\n                }\n            }\n        }\n\n        private void Close()\n        {\n            this.Cancel();\n\n            var proc = this.process;\n            this.process = null;\n            if (proc != null)\n            {\n                try\n                {\n                    this.UnRegisterProcessEvents(proc);\n\n                    // Dispose in all cases.\n                    proc.Close();\n                    proc.Dispose();\n                }\n                catch (Exception ex)\n                {\n                    this.OnProcessErrorCore(ex);\n                }\n            }\n        }\n\n        protected virtual void OnDispose()\n        {\n        }\n\n        void IDisposable.Dispose()\n        {\n            this.IsDisposed = true;\n            this.Close();\n            this.OnDispose();\n        }\n\n        public override string ToString()\n        {\n            return string.Format(\"{0}: {1} {2}\", this.GetType().Name, this.Name, this.process);\n        }\n\n        protected virtual bool OnBeforeStartProcessCore(RunnerParams processRunnerInfo)\n        {\n            return true;\n        }\n\n        protected virtual void OnProcessStartedCore()\n        {\n        }\n\n        protected virtual void OnProcessErrorCore(Exception processException)\n        {\n        }\n\n        protected virtual void OnProcessExitCore(int exitCode)\n        {\n        }\n\n        private void RegisterProcessEvents(Process proc)\n        {\n            proc.ErrorDataReceived += this.Process_ErrorDataReceived;\n            proc.OutputDataReceived += this.Process_OutputDataReceived;\n            proc.Exited += this.Process_Exited;\n        }\n\n        private void UnRegisterProcessEvents(Process proc)\n        {\n            proc.ErrorDataReceived -= this.Process_ErrorDataReceived;\n            proc.OutputDataReceived -= this.Process_OutputDataReceived;\n            proc.Exited -= this.Process_Exited;\n        }\n\n        private void Process_Exited(object sender, EventArgs e)\n        {\n            this.WaitForExitAfterExited();\n            this.SetExitCode();\n            this.OnProcessExitCore(this.LastExitCode ?? -9998);\n            this.ProcessExited?.Invoke(this, new EventArgs());\n        }\n\n        private void WaitForExitAfterExited()\n        {\n            try\n            {\n                // This shouldn't throw here, but the mono process implementation doesn't always behave as it should.\n                this.process.WaitForExit();\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine(\"Error when calling WaitForExit after exited event has fired: {0}.{1}: {2}\", ex, nameof(ProcessRunner), nameof(this.WaitForExitAfterExited));\n            }\n        }\n\n        private void SetExitCode()\n        {\n            int exitCode = -9999;\n\n            try\n            {\n                if (this.Process != null)\n                {\n                    exitCode = this.Process.ExitCode;\n                }\n            }\n            catch\n            {\n                // Ignore error.\n            }\n\n            this.LastExitCode = exitCode;\n        }\n\n        private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)\n        {\n            if (this.RecordStandardError)\n            {\n                lock (this.stdErr)\n                {\n                    this.stdErr.AppendLine(e.Data);\n                }\n            }\n\n            if (e.Data != null)\n            {\n                Console.WriteLine(\"|| \" + e.Data);\n            }\n            else\n            {\n                var evt = this.stdErrEvent;\n                if (evt != null)\n                {\n                    lock (evt)\n                    {\n                        try\n                        {\n                            evt.Set();\n                        }\n                        catch\n                        {\n                            // Ignore error.\n                        }\n                    }\n                }\n            }\n        }\n\n        private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)\n        {\n            if (this.RecordStandardOutput)\n            {\n                lock (this.stdOut)\n                {\n                    this.stdOut.AppendLine(e.Data);\n                }\n            }\n\n            if (e.Data != null)\n            {\n                Console.WriteLine(\"|| \" + e.Data);\n            }\n            else\n            {\n                var evt = this.stdOutEvent;\n                if (evt != null)\n                {\n                    lock (evt)\n                    {\n                        try\n                        {\n                            evt.Set();\n                        }\n                        catch\n                        {\n                            // Ignore error.\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Common/RunnerParams.cs",
    "content": "﻿namespace ElectronNET.Common\n{\n    using System;\n    using System.Collections.Generic;\n    using System.ComponentModel;\n    using System.Diagnostics;\n    using System.Text;\n\n    public sealed class RunnerParams\n    {\n        private string fileName;\n        private string arguments;\n        private string directory;\n        private string userName;\n        private string verb;\n        private ProcessWindowStyle windowStyle;\n\n        /// <summary>\n        ///     Default constructor.  At least the <see cref='ProcessStartInfo.FileName'/>\n        ///     property must be set before starting the process.\n        /// </summary>\n        public RunnerParams()\n        {\n        }\n\n        /// <summary>\n        ///     Specifies the name of the application or document that is to be started.\n        /// </summary>\n        public RunnerParams(string fileName)\n        {\n            this.fileName = fileName;\n        }\n\n        /// <summary>\n        ///     Specifies the name of the application that is to be started, as well as a set\n        ///     of command line arguments to pass to the application.\n        /// </summary>\n        public RunnerParams(string fileName, string arguments)\n        {\n            this.fileName = fileName;\n            this.arguments = arguments;\n        }\n\n        /// <summary>\n        ///     Specifies the set of command line arguments to use when starting the application.\n        /// </summary>\n        public string Arguments\n        {\n            get\n            {\n                return this.arguments ?? string.Empty;\n            }\n\n            set\n            {\n                this.arguments = value;\n            }\n        }\n\n        public bool CreateNoWindow { get; set; }\n\n        public Dictionary<string, string> EnvironmentVariables { get; set; } = new Dictionary<string, string>();\n\n        public bool RedirectStandardInput { get; set; }\n\n        public bool RedirectStandardOutput { get; set; }\n\n        public bool RedirectStandardError { get; set; }\n\n        public Encoding StandardInputEncoding { get; set; }\n\n        public Encoding StandardErrorEncoding { get; set; }\n\n        public Encoding StandardOutputEncoding { get; set; }\n\n        /// <summary>\n        ///    <para>\n        ///       Returns or sets the application, document, or URL that is to be launched.\n        ///    </para>\n        /// </summary>\n        public string FileName\n        {\n            get\n            {\n                return this.fileName ?? string.Empty;\n            }\n\n            set\n            {\n                this.fileName = value;\n            }\n        }\n\n        /// <summary>\n        ///     Returns or sets the initial directory for the process that is started.\n        ///     Specify \"\" to if the default is desired.\n        /// </summary>\n        public string WorkingDirectory\n        {\n            get\n            {\n                return this.directory ?? string.Empty;\n            }\n\n            set\n            {\n                this.directory = value;\n            }\n        }\n\n        public bool ErrorDialog { get; set; }\n\n        public IntPtr ErrorDialogParentHandle { get; set; }\n\n        public string UserName\n        {\n            get\n            {\n                return this.userName ?? string.Empty;\n            }\n\n            set\n            {\n                this.userName = value;\n            }\n        }\n\n        [DefaultValue(\"\")]\n        public string Verb\n        {\n            get\n            {\n                return this.verb ?? string.Empty;\n            }\n\n            set\n            {\n                this.verb = value;\n            }\n        }\n\n        [DefaultValue(ProcessWindowStyle.Normal)]\n        public ProcessWindowStyle WindowStyle\n        {\n            get\n            {\n                return this.windowStyle;\n            }\n\n            set\n            {\n                if (!Enum.IsDefined(typeof(ProcessWindowStyle), value))\n                {\n                    throw new InvalidEnumArgumentException(nameof(value), (int)value, typeof(ProcessWindowStyle));\n                }\n\n                this.windowStyle = value;\n            }\n        }\n\n        public bool UseShellExecute { get; set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Common/TimeSpanExtensions.cs",
    "content": "﻿// <copyright file=\"TimeSpanExtensions.cs\" company=\"Emby LLC\">\n// Copyright © Emby LLC. All rights reserved.\n// </copyright>\n\nnamespace ElectronNET.Common\n{\n    using System;\n    using System.Diagnostics.CodeAnalysis;\n\n    /// <summary>\n    /// The TimeSpanExtensions class.\n    /// </summary>\n    [SuppressMessage(\"StyleCop.CSharp.NamingRules\", \"SA1300:Element should begin with upper-case letter\", Justification = \"OK\")]\n    [SuppressMessage(\"StyleCop.CSharp.DocumentationRules\", \"SA1600:Elements should be documented\", Justification = \"OK\")]\n    [SuppressMessage(\"ReSharper\", \"StyleCop.SA1300\", Justification = \"OK\")]\n    [SuppressMessage(\"ReSharper\", \"InconsistentNaming\", Justification = \"OK\")]\n    internal static class TimeSpanExtensions\n    {\n        public static TimeSpan ms(this int value)\n        {\n            return TimeSpan.FromMilliseconds(value);\n        }\n\n        public static TimeSpan ms(this long value)\n        {\n            return TimeSpan.FromMilliseconds(value);\n        }\n\n        public static TimeSpan seconds(this int value)\n        {\n            return TimeSpan.FromSeconds(value);\n        }\n\n        public static TimeSpan minutes(this int value)\n        {\n            return TimeSpan.FromMinutes(value);\n        }\n\n        public static TimeSpan hours(this int value)\n        {\n            return TimeSpan.FromHours(value);\n        }\n\n        public static TimeSpan days(this int value)\n        {\n            return TimeSpan.FromDays(value);\n        }\n\n        public static TimeSpan ms(this double value)\n        {\n            return TimeSpan.FromMilliseconds(value);\n        }\n\n        public static TimeSpan seconds(this double value)\n        {\n            return TimeSpan.FromSeconds(value);\n        }\n\n        public static TimeSpan minutes(this double value)\n        {\n            return TimeSpan.FromMinutes(value);\n        }\n\n        public static TimeSpan hours(this double value)\n        {\n            return TimeSpan.FromHours(value);\n        }\n\n        public static TimeSpan days(this double value)\n        {\n            return TimeSpan.FromDays(value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.API/Converter/ModifierTypeListConverter.cs",
    "content": "﻿namespace ElectronNET.Converter;\n\nusing ElectronNET.API.Entities;\nusing System;\nusing System.Collections.Generic;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\n/// <summary>\n/// \n/// </summary>\npublic class ModifierTypeListConverter : JsonConverter<List<ModifierType>>\n{\n    public override List<ModifierType> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (reader.TokenType == JsonTokenType.Null)\n        {\n            return null;\n        }\n\n        var list = new List<ModifierType>();\n        if (reader.TokenType != JsonTokenType.StartArray)\n        {\n            throw new JsonException(\"Expected array for ModifierType list\");\n        }\n\n        while (reader.Read())\n        {\n            if (reader.TokenType == JsonTokenType.EndArray) break;\n            if (reader.TokenType != JsonTokenType.String) throw new JsonException(\"Expected string enum value\");\n            var s = reader.GetString();\n            list.Add((ModifierType)Enum.Parse(typeof(ModifierType), s, ignoreCase: true));\n        }\n\n        return list;\n    }\n\n    public override void Write(Utf8JsonWriter writer, List<ModifierType> value, JsonSerializerOptions options)\n    {\n        writer.WriteStartArray();\n        foreach (var modifier in value)\n        {\n            writer.WriteStringValue(modifier.ToString().ToLowerInvariant());\n        }\n\n        writer.WriteEndArray();\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Converter/PageSizeConverter.cs",
    "content": "using ElectronNET.API.Entities;\nusing ElectronNET.API.Serialization;\nusing System;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace ElectronNET.Converter;\n\npublic class PageSizeConverter : JsonConverter<PageSize>\n{\n    public override PageSize Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (reader.TokenType == JsonTokenType.String)\n        {\n            return reader.GetString();\n        }\n        else if (reader.TokenType == JsonTokenType.StartObject)\n        {\n            return JsonSerializer.Deserialize<PageSize>(ref reader, ElectronJson.Options);\n        }\n        else\n        {\n            throw new JsonException(\"Invalid value for PageSize. Expected string or an object.\");\n        }\n    }\n\n    public override void Write(Utf8JsonWriter writer, PageSize value, JsonSerializerOptions options)\n    {\n        if (value is null)\n        {\n            return;\n        }\n\n        var str = (string)value;\n\n        if (str is not null)\n        {\n            writer.WriteStringValue(str);\n        }\n        else\n        {\n            JsonSerializer.Serialize(writer, value, ElectronJson.Options);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Converter/TitleBarOverlayConverter.cs",
    "content": "using ElectronNET.API.Entities;\nusing ElectronNET.API.Serialization;\nusing System;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace ElectronNET.Converter;\n\npublic class TitleBarOverlayConverter : JsonConverter<TitleBarOverlay>\n{\n    public override TitleBarOverlay Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (reader.TokenType == JsonTokenType.True || reader.TokenType == JsonTokenType.False)\n        {\n            return (bool)reader.GetBoolean();\n        }\n        else if (reader.TokenType == JsonTokenType.StartObject)\n        {\n            using var doc = JsonDocument.ParseValue(ref reader);\n            return doc.RootElement.Deserialize<TitleBarOverlay>(ElectronJson.Options);\n        }\n        else\n        {\n            throw new JsonException(\"Invalid value for TitleBarOverlay. Expected boolean or an object.\");\n        }\n    }\n\n    public override void Write(Utf8JsonWriter writer, TitleBarOverlay value, JsonSerializerOptions options)\n    {\n        if (value is null)\n        {\n            return;\n        }\n\n        var @bool = (bool?)value;\n        if (@bool.HasValue)\n        {\n            writer.WriteBooleanValue(@bool.Value);\n        }\n        else\n        {\n            JsonSerializer.Serialize(writer, value, ElectronJson.Options);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/ElectronNET.API.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"..\\common.props\" />\n\n  <PropertyGroup>\n    <TargetFrameworks>net6.0;net8.0;net10.0</TargetFrameworks>\n    <PackageOutputPath>..\\..\\artifacts</PackageOutputPath>\n    <PackageId>$(PackageNamePrefix).API</PackageId>\n    <Title>$(PackageId)</Title>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <IncludeSymbols>True</IncludeSymbols>\n    <SymbolPackageFormat>snupkg</SymbolPackageFormat>\n    <Nullable>disable</Nullable>\n    <Description>$(DescriptionFirstPart) This package contains the API to access the \"native\" electron API.</Description>\n    <RootNamespace>ElectronNET</RootNamespace>\n    <NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>\n  </PropertyGroup>\n  <ItemGroup>\n    <None Remove=\"ElectronNET.API.csproj.DotSettings\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"PackageIcon.png\" Pack=\"true\" PackagePath=\"\\\" />\n    <None Include=\"../../README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.SourceLink.GitHub\" Version=\"8.0.0\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"SocketIOClient\" Version=\"3.1.2\" />\n    <PackageReference Include=\"System.Drawing.Common\" Version=\"8.0.22\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"8.0.6\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"ElectronNET.AspNet\" />\n    <InternalsVisibleTo Include=\"ElectronNET.Core.AspNet\" />\n    <InternalsVisibleTo Include=\"ElectronNET.IntegrationTests\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/ElectronNET.API/ElectronNET.API.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:String x:Key=\"/Default/CodeInspection/Daemon/ConfigureAwaitAnalysisMode/@EntryValue\">Library</s:String>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=entities/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "src/ElectronNET.API/ElectronNetRuntime.cs",
    "content": "﻿namespace ElectronNET\n{\n    using ElectronNET.API;\n    using ElectronNET.Runtime;\n    using ElectronNET.Runtime.Controllers;\n    using ElectronNET.Runtime.Data;\n    using System;\n    using System.Collections.Immutable;\n    using System.Threading.Tasks;\n\n    public static class ElectronNetRuntime\n    {\n        internal static StartupManager StartupManager;\n\n        internal const int DefaultSocketPort = 8000;\n        internal const int DefaultWebPort = 8001;\n        internal const string ElectronPortArgumentName = \"electronPort\";\n        internal const string ElectronPidArgumentName = \"electronPID\";\n\n        /// <summary>Initializes the <see cref=\"ElectronNetRuntime\"/> class.</summary>\n        static ElectronNetRuntime()\n        {\n            StartupManager = new StartupManager();\n            StartupManager.Initialize();\n        }\n\n        public static string ElectronExtraArguments { get; set; }\n\n        public static int? ElectronSocketPort { get; internal set; }\n\n        public static int? AspNetWebPort { get; internal set; }\n\n        public static StartupMethod StartupMethod { get; internal set; }\n\n        public static DotnetAppType DotnetAppType { get; internal set; }\n\n        public static string ElectronExecutable { get; internal set; }\n\n        public static ImmutableList<string> ProcessArguments { get; internal set; }\n\n        public static BuildInfo BuildInfo { get; internal set; }\n\n        public static IElectronNetRuntimeController RuntimeController => RuntimeControllerCore;\n\n        // The below properties are non-public\n        internal static RuntimeControllerBase RuntimeControllerCore { get; set; }\n\n        internal static int? ElectronProcessId { get; set; }\n\n        internal static Func<Task> OnAppReadyCallback { get; set; }\n\n        internal static SocketIoFacade GetSocket()\n        {\n            return RuntimeControllerCore?.Socket;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Controllers/RuntimeControllerBase.cs",
    "content": "﻿namespace ElectronNET.Runtime.Controllers\n{\n    using ElectronNET.API;\n    using ElectronNET.Runtime.Services;\n    using ElectronNET.Runtime.Services.ElectronProcess;\n    using ElectronNET.Runtime.Services.SocketBridge;\n    using System.Threading.Tasks;\n\n    internal abstract class RuntimeControllerBase : LifetimeServiceBase, IElectronNetRuntimeController\n    {\n        protected RuntimeControllerBase()\n        {\n        }\n\n        internal abstract SocketIoFacade Socket { get; }\n\n        internal abstract ElectronProcessBase ElectronProcess { get; }\n\n        internal abstract SocketBridgeService SocketBridge { get; }\n\n        protected override Task StartCore()\n        {\n            return Task.CompletedTask;\n        }\n\n        protected override Task StopCore()\n        {\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Controllers/RuntimeControllerDotNetFirst.cs",
    "content": "﻿namespace ElectronNET.Runtime.Controllers\n{\n    using ElectronNET.API;\n    using ElectronNET.Common;\n    using ElectronNET.Runtime.Data;\n    using ElectronNET.Runtime.Helpers;\n    using ElectronNET.Runtime.Services.ElectronProcess;\n    using ElectronNET.Runtime.Services.SocketBridge;\n    using System;\n    using System.Threading.Tasks;\n\n    internal class RuntimeControllerDotNetFirst : RuntimeControllerBase\n    {\n        private ElectronProcessBase electronProcess;\n        private SocketBridgeService socketBridge;\n        private int? port;\n\n        public RuntimeControllerDotNetFirst()\n        {\n        }\n\n        internal override SocketIoFacade Socket\n        {\n            get\n            {\n                if (this.State == LifetimeState.Ready)\n                {\n                    return this.socketBridge.Socket;\n                }\n\n                throw new Exception(\"Cannot access socket bridge. Runtime is not in 'Ready' state\");\n            }\n        }\n\n        internal override ElectronProcessBase ElectronProcess => this.electronProcess;\n\n        internal override SocketBridgeService SocketBridge => this.socketBridge;\n\n        protected override Task StartCore()\n        {\n            var isUnPacked = ElectronNetRuntime.StartupMethod.IsUnpackaged();\n            var electronBinaryName = ElectronNetRuntime.ElectronExecutable;\n            var args = string.Format(\"{0} {1}\", ElectronNetRuntime.ElectronExtraArguments, Environment.CommandLine).Trim();\n            this.port = ElectronNetRuntime.ElectronSocketPort;\n\n            if (!this.port.HasValue)\n            {\n                this.port = PortHelper.GetFreePort(ElectronNetRuntime.DefaultSocketPort);\n                ElectronNetRuntime.ElectronSocketPort = this.port;\n            }\n\n            Console.Error.WriteLine(\"[StartCore]: isUnPacked: {0}\", isUnPacked);\n            Console.Error.WriteLine(\"[StartCore]: electronBinaryName: {0}\", electronBinaryName);\n            Console.Error.WriteLine(\"[StartCore]: args: {0}\", args);\n\n            this.electronProcess = new ElectronProcessActive(isUnPacked, electronBinaryName, args, this.port.Value);\n            this.electronProcess.Ready += this.ElectronProcess_Ready;\n            this.electronProcess.Stopped += this.ElectronProcess_Stopped;\n\n            Console.Error.WriteLine(\"[StartCore]: Before Start\");\n            return this.electronProcess.Start();\n        }\n\n        private void ElectronProcess_Ready(object sender, EventArgs e)\n        {\n            this.TransitionState(LifetimeState.Started);\n            this.socketBridge = new SocketBridgeService(this.port!.Value);\n            this.socketBridge.Ready += this.SocketBridge_Ready;\n            this.socketBridge.Stopped += this.SocketBridge_Stopped;\n            this.socketBridge.Start();\n        }\n\n        private void SocketBridge_Ready(object sender, EventArgs e)\n        {\n            this.TransitionState(LifetimeState.Ready);\n        }\n\n        private void SocketBridge_Stopped(object sender, EventArgs e)\n        {\n            this.HandleStopped();\n        }\n\n        private void ElectronProcess_Stopped(object sender, EventArgs e)\n        {\n            this.HandleStopped();\n        }\n\n        private void HandleStopped()\n        {\n            if (this.socketBridge != null && this.socketBridge.State != LifetimeState.Stopped)\n            {\n                this.socketBridge.Stop();\n            }\n            else if (this.electronProcess != null && this.electronProcess.State != LifetimeState.Stopped)\n            {\n                this.electronProcess.Stop();\n            }\n            else\n            {\n                this.TransitionState(LifetimeState.Stopped);\n            }\n        }\n\n        protected override Task StopCore()\n        {\n            this.electronProcess.Stop();\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Controllers/RuntimeControllerElectronFirst.cs",
    "content": "﻿namespace ElectronNET.Runtime.Controllers\n{\n    using ElectronNET.API;\n    using ElectronNET.Runtime.Data;\n    using ElectronNET.Runtime.Services.ElectronProcess;\n    using ElectronNET.Runtime.Services.SocketBridge;\n    using System;\n    using System.Threading.Tasks;\n\n    internal class RuntimeControllerElectronFirst : RuntimeControllerBase\n    {\n        private ElectronProcessBase electronProcess;\n        private SocketBridgeService socketBridge;\n        private int? port;\n\n        public RuntimeControllerElectronFirst()\n        {\n        }\n\n        internal override SocketIoFacade Socket\n        {\n            get\n            {\n                if (this.State == LifetimeState.Ready)\n                {\n                    return this.socketBridge.Socket;\n                }\n\n                throw new Exception(\"Cannot access socket bridge. Runtime is not in 'Ready' state\");\n            }\n        }\n\n        internal override ElectronProcessBase ElectronProcess => this.electronProcess;\n\n        internal override SocketBridgeService SocketBridge => this.socketBridge;\n\n        protected override Task StartCore()\n        {\n            this.port = ElectronNetRuntime.ElectronSocketPort;\n\n            if (!this.port.HasValue)\n            {\n                throw new Exception(\"No port has been specified by Electron!\");\n            }\n\n            if (!ElectronNetRuntime.ElectronProcessId.HasValue)\n            {\n                throw new Exception(\"No electronPID has been specified by Electron!\");\n            }\n\n            this.TransitionState(LifetimeState.Starting);\n            this.socketBridge = new SocketBridgeService(this.port!.Value);\n            this.socketBridge.Ready += this.SocketBridge_Ready;\n            this.socketBridge.Stopped += this.SocketBridge_Stopped;\n            this.socketBridge.Start();\n\n            this.electronProcess = new ElectronProcessPassive(ElectronNetRuntime.ElectronProcessId.Value);\n            this.electronProcess.Ready += this.ElectronProcess_Ready;\n            this.electronProcess.Stopped += this.ElectronProcess_Stopped;\n\n            this.electronProcess.Start();\n\n            return Task.CompletedTask;\n        }\n\n        private void ElectronProcess_Ready(object sender, EventArgs e)\n        {\n        }\n\n        private void SocketBridge_Ready(object sender, EventArgs e)\n        {\n            this.TransitionState(LifetimeState.Ready);\n        }\n\n        private void SocketBridge_Stopped(object sender, EventArgs e)\n        {\n            this.HandleStopped();\n        }\n\n        private void ElectronProcess_Stopped(object sender, EventArgs e)\n        {\n            this.HandleStopped();\n        }\n\n        private void HandleStopped()\n        {\n            if (this.socketBridge.State != LifetimeState.Stopped)\n            {\n                this.socketBridge.Stop();\n            }\n            else if (this.electronProcess.State != LifetimeState.Stopped)\n            {\n                this.electronProcess.Stop();\n            }\n            else\n            {\n                this.TransitionState(LifetimeState.Stopped);\n            }\n        }\n\n        protected override Task StopCore()\n        {\n            this.socketBridge.Stop();\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Data/BuildInfo.cs",
    "content": "﻿namespace ElectronNET.Runtime.Data\n{\n    public class BuildInfo\n    {\n        public string ElectronExecutable { get; internal set; }\n\n        public string ElectronVersion { get; internal set; }\n\n        public string RuntimeIdentifier { get; internal set; }\n\n        public bool ElectronSingleInstance { get; internal set; }\n\n        public string Title { get; internal set; }\n\n        public string Version { get; internal set; }\n\n        public string BuildConfiguration { get; internal set; }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Data/DotnetAppType.cs",
    "content": "﻿namespace ElectronNET.Runtime.Data\n{\n    public enum DotnetAppType\n    {\n        /// <summary>A plain DotNet cross-platform console app.</summary>\n        ConsoleApp,\n\n        /// <summary>ASP.NET Core cross-platform app.</summary>\n        AspNetCoreApp,\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Data/LifetimeState.cs",
    "content": "﻿namespace ElectronNET.Runtime.Data\n{\n    public enum LifetimeState\n    {\n        Uninitialized,\n        Starting,\n        Started,\n        Ready,\n        Stopping,\n        Stopped,\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Data/StartupMethod.cs",
    "content": "﻿namespace ElectronNET.Runtime.Data\n{\n    public enum StartupMethod\n    {\n        /// <summary>Packaged Electron app where Electron launches the DotNet app.</summary>\n        /// <remarks>\n        ///     This is the classic way of ElectrronNET startup.\n        /// </remarks>\n        PackagedElectronFirst,\n\n        /// <summary>Packaged Electron app where DotNet launches the Electron prozess.</summary>\n        /// <remarks>\n        ///     Provides better ways for managing the overall app lifecycle.\n        ///     On the command lines, this is \"dotnetpacked\"\n        /// </remarks>\n        PackagedDotnetFirst,\n\n        /// <summary>Unpackacked execution for debugging the Electron process and NodeJS.</summary>\n        /// <remarks>\n        ///     Similar to the legacy ElectronNET debugging but without packaging (=fast) and allows selection of\n        ///     the debug adapter. It's rarely useful, unless it's about debugging NodeJS.\n        ///     Note: 'Unpackaged' means that it's run directly from the compilation output folders (./bin/*).\n        ///     On the command lines, this is \"unpackedelectron\"\n        /// </remarks>\n        UnpackedElectronFirst,\n\n\n        /// <summary>Unpackacked execution for debugging the DotNet process.</summary>\n        /// <remarks>\n        ///     This is the new way of super-fast startup for debugging in-place with Hot Reload\n        ///     (edit and continue), even on WSL - all from within Visual Studio.\n        ///     Note: 'Unpackaged' means that it's run directly from the compilation output folders (./bin/*).\n        ///     On the command lines, this is \"unpackeddotnet\"\n        /// </remarks>\n        UnpackedDotnetFirst,\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Helpers/LaunchOrderDetector.cs",
    "content": "﻿namespace ElectronNET.Runtime.Helpers\n{\n    using System;\n    using System.Collections.Generic;\n    using System.Diagnostics;\n    using System.Linq;\n\n    internal class LaunchOrderDetector\n    {\n        public static bool CheckIsLaunchedByDotNet()\n        {\n            var tests = new List<Func<bool?>>();\n\n            tests.Add(CheckIsDotNetStartup1);\n            tests.Add(CheckIsDotNetStartup2);\n            tests.Add(CheckIsDotNetStartup3);\n\n            int scoreDotNet = 0, scoreElectron = 0;\n\n            foreach (var test in tests)\n            {\n                var res = test();\n\n                if (res == true)\n                {\n                    scoreDotNet++;\n                }\n\n                if (res == false)\n                {\n                    scoreElectron++;\n                }\n            }\n\n            Console.WriteLine(\"Probe scored for launch origin:   DotNet {0} vs. {1} Electron\", scoreDotNet, scoreElectron);\n            return scoreDotNet > scoreElectron;\n        }\n\n        private static bool? CheckIsDotNetStartup1()\n        {\n            var hasPortArg = ElectronNetRuntime.ProcessArguments.Any(e => e.Contains(ElectronNetRuntime.ElectronPortArgumentName, StringComparison.OrdinalIgnoreCase));\n            if (hasPortArg)\n            {\n                return false;\n            }\n\n\n            return true;\n        }\n\n        private static bool? CheckIsDotNetStartup2()\n        {\n            var hasPidArg = ElectronNetRuntime.ProcessArguments.Any(e => e.Contains(ElectronNetRuntime.ElectronPidArgumentName, StringComparison.OrdinalIgnoreCase));\n            if (hasPidArg)\n            {\n                return false;\n            }\n\n            return true;\n        }\n\n        private static bool? CheckIsDotNetStartup3()\n        {\n            if (Debugger.IsAttached)\n            {\n                return true;\n            }\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Helpers/PortHelper.cs",
    "content": "﻿namespace ElectronNET.Runtime.Helpers\n{\n    using System.Linq;\n    using System.Net.NetworkInformation;\n\n    internal static class PortHelper\n    {\n        public static int GetFreePort(int? defaultPost)\n        {\n            var listeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Select(e => e.Port).ToList();\n\n            int port = defaultPost ?? 8000;\n\n            while (true)\n            {\n                if (!listeners.Contains(port))\n                {\n                    return port;\n                }\n\n                port += 2;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Helpers/UnpackagedDetector.cs",
    "content": "﻿namespace ElectronNET.Runtime.Helpers\n{\n    using System;\n    using System.Collections.Generic;\n    using System.Diagnostics;\n    using System.IO;\n    using System.Linq;\n\n    internal class UnpackagedDetector\n    {\n        public static bool CheckIsUnpackaged()\n        {\n            var tests = new List<Func<bool?>>();\n\n            tests.Add(CheckUnpackaged1);\n\n            // We let this one account twice\n            tests.Add(CheckUnpackaged2);\n            tests.Add(CheckUnpackaged2);\n\n            tests.Add(CheckUnpackaged3);\n            tests.Add(CheckUnpackaged4);\n\n            int scoreUnpackaged = 0, scorePackaged = 0;\n\n            foreach (var test in tests)\n            {\n                var res = test();\n\n                if (res == true)\n                {\n                    scoreUnpackaged++;\n                }\n\n                if (res == false)\n                {\n                    scorePackaged++;\n                }\n            }\n\n            Console.WriteLine(\"Probe scored for package mode:   Unpackaged {0} vs. {1} Packaged\", scoreUnpackaged, scorePackaged);\n            return scoreUnpackaged > scorePackaged;\n        }\n\n        private static bool? CheckUnpackaged1()\n        {\n            var cfg = ElectronNetRuntime.BuildInfo.BuildConfiguration;\n            if (cfg != null)\n            {\n                if (cfg.Equals(\"Debug\", StringComparison.OrdinalIgnoreCase))\n                {\n                    return true;\n                }\n\n                if (cfg.Equals(\"Release\", StringComparison.OrdinalIgnoreCase))\n                {\n                    return false;\n                }\n            }\n\n            return null;\n        }\n\n        private static bool? CheckUnpackaged2()\n        {\n            var dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);\n            if (dir.Name == \"bin\" && dir.Parent?.Name == \"resources\")\n            {\n                return false;\n            }\n\n            if (dir.GetDirectories().Any(e => e.Name == \".electron\"))\n            {\n                return true;\n            }\n\n            return null;\n        }\n\n        private static bool? CheckUnpackaged3()\n        {\n            if (Debugger.IsAttached)\n            {\n                return true;\n            }\n\n\n            return null;\n        }\n\n        private static bool? CheckUnpackaged4()\n        {\n            var isUnpackaged = ElectronNetRuntime.ProcessArguments.Any(e => e.Contains(\"unpacked\", StringComparison.OrdinalIgnoreCase));\n\n            if (isUnpackaged)\n            {\n                return true;\n            }\n\n            var isPackaged = ElectronNetRuntime.ProcessArguments.Any(e => e.Contains(\"dotnetpacked\", StringComparison.OrdinalIgnoreCase));\n            if (isPackaged)\n            {\n                return false;\n            }\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/IElectronNetRuntimeController.cs",
    "content": "﻿namespace ElectronNET.Runtime\n{\n    using ElectronNET.Runtime.Data;\n    using System;\n    using System.Threading.Tasks;\n\n    public interface IElectronNetRuntimeController\n    {\n        LifetimeState State { get; }\n\n        Task WaitStartedTask { get; }\n\n        Task WaitReadyTask { get; }\n\n        Task WaitStoppingTask { get; }\n\n        Task WaitStoppedTask { get; }\n\n        event EventHandler Starting;\n\n        event EventHandler Started;\n\n        event EventHandler Ready;\n\n        event EventHandler Stopping;\n\n        event EventHandler Stopped;\n\n        Task Start();\n\n        Task Stop();\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Services/ElectronProcess/ElectronProcessActive.cs",
    "content": "﻿namespace ElectronNET.Runtime.Services.ElectronProcess\n{\n    using System;\n    using System.ComponentModel;\n    using System.IO;\n    using System.Linq;\n    using System.Runtime.InteropServices;\n    using System.Threading.Tasks;\n    using ElectronNET.Common;\n    using ElectronNET.Runtime.Data;\n\n    /// <summary>\n    /// Launches and manages the Electron app process.\n    /// </summary>\n    [Localizable(false)]\n    internal class ElectronProcessActive : ElectronProcessBase\n    {\n        private readonly bool isUnpackaged;\n        private readonly string electronBinaryName;\n        private readonly string extraArguments;\n        private readonly int socketPort;\n        private ProcessRunner process;\n\n        /// <summary>Initializes a new instance of the <see cref=\"ElectronProcessActive\"/> class.</summary>\n        /// <param name=\"isUnpackaged\">The is debug.</param>\n        /// <param name=\"electronBinaryName\">Name of the electron.</param>\n        /// <param name=\"extraArguments\">The extraArguments.</param>\n        /// <param name=\"socketPort\">The socket port.</param>\n        public ElectronProcessActive(bool isUnpackaged, string electronBinaryName, string extraArguments, int socketPort)\n        {\n            this.isUnpackaged = isUnpackaged;\n            this.electronBinaryName = electronBinaryName;\n            this.extraArguments = extraArguments;\n            this.socketPort = socketPort;\n        }\n\n        protected override async Task StartCore()\n        {\n            var dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);\n            string startCmd, args, workingDir;\n\n            if (this.isUnpackaged)\n            {\n                this.CheckRuntimeIdentifier();\n\n                var electrondir = Path.Combine(dir.FullName, \".electron\");\n\n                ProcessRunner chmodRunner = null;\n\n                try\n                {\n                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                    {\n                        var distFolder = Path.Combine(electrondir, \"node_modules\", \"electron\", \"dist\");\n\n                        chmodRunner = new ProcessRunner(\"ElectronRunner-Chmod\");\n                        chmodRunner.Run(\"chmod\", \"-R +x \" + distFolder, electrondir);\n                        await chmodRunner.WaitForExitAsync().ConfigureAwait(true);\n\n                        if (chmodRunner.LastExitCode != 0)\n                        {\n                            throw new Exception(\"Failed to set executable permissions on Electron dist folder.\");\n                        }\n                    }\n                }\n                catch (Exception ex)\n                {\n                    Console.Error.WriteLine(\"[StartCore]: Exception: \" + chmodRunner?.StandardError);\n                    Console.Error.WriteLine(\"[StartCore]: Exception: \" + chmodRunner?.StandardOutput);\n                    Console.Error.WriteLine(\"[StartCore]: Exception: \" + ex);\n                }\n\n                startCmd = Path.Combine(electrondir, \"node_modules\", \"electron\", \"dist\", \"electron\");\n\n                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n                {\n                    startCmd = Path.Combine(electrondir, \"node_modules\", \"electron\", \"dist\", \"Electron.app\", \"Contents\", \"MacOS\", \"Electron\");\n                }\n\n                args = $\"main.js -unpackeddotnet --trace-warnings -electronforcedport={this.socketPort:D} \" + this.extraArguments;\n                workingDir = electrondir;\n            }\n            else\n            {\n                dir = dir.Parent!.Parent!;\n                startCmd = Path.Combine(dir.FullName, this.electronBinaryName);\n                args = $\"-dotnetpacked -electronforcedport={this.socketPort:D} \" + this.extraArguments;\n                workingDir = dir.FullName;\n            }\n\n            // We don't await this in order to let the state transition to \"Starting\"\n            Task.Run(async () => await this.StartInternal(startCmd, args, workingDir).ConfigureAwait(false));\n        }\n\n        private void CheckRuntimeIdentifier()\n        {\n            var buildInfoRid = ElectronNetRuntime.BuildInfo.RuntimeIdentifier;\n            if (string.IsNullOrEmpty(buildInfoRid))\n            {\n                return;\n            }\n\n            var osPart = buildInfoRid.Split('-').First();\n\n            var mismatch = false;\n\n            switch (osPart)\n            {\n                case \"win\":\n\n                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                    {\n                        mismatch = true;\n                    }\n\n                    break;\n\n                case \"linux\":\n\n                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\n                    {\n                        mismatch = true;\n                    }\n\n                    break;\n\n                case \"osx\":\n\n                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n                    {\n                        mismatch = true;\n                    }\n\n                    break;\n\n                case \"freebsd\":\n\n                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))\n                    {\n                        mismatch = true;\n                    }\n\n                    break;\n            }\n\n            if (mismatch)\n            {\n                throw new PlatformNotSupportedException($\"This Electron.NET application was built for '{buildInfoRid}'. It cannot run on this platform.\");\n            }\n        }\n\n        protected override Task StopCore()\n        {\n            this.process.Cancel();\n            return Task.CompletedTask;\n        }\n\n        private async Task StartInternal(string startCmd, string args, string directoriy)\n        {\n            try\n            {\n                await Task.Delay(10.ms()).ConfigureAwait(false);\n\n                Console.Error.WriteLine(\"[StartInternal]: startCmd: {0}\", startCmd);\n                Console.Error.WriteLine(\"[StartInternal]: args: {0}\", args);\n\n                this.process = new ProcessRunner(\"ElectronRunner\");\n                this.process.ProcessExited += this.Process_Exited;\n                this.process.Run(startCmd, args, directoriy);\n\n                await Task.Delay(500.ms()).ConfigureAwait(false);\n\n                Console.Error.WriteLine(\"[StartInternal]: after run:\");\n\n                if (!this.process.IsRunning)\n                {\n                    Console.Error.WriteLine(\"[StartInternal]: Process is not running: \" + this.process.StandardError);\n                    Console.Error.WriteLine(\"[StartInternal]: Process is not running: \" + this.process.StandardOutput);\n\n                    Task.Run(() => this.TransitionState(LifetimeState.Stopped));\n\n                    throw new Exception(\"Failed to launch the Electron process.\");\n                }\n\n                this.TransitionState(LifetimeState.Ready);\n            }\n            catch (Exception ex)\n            {\n                Console.Error.WriteLine(\"[StartInternal]: Exception: \" + this.process?.StandardError);\n                Console.Error.WriteLine(\"[StartInternal]: Exception: \" + this.process?.StandardOutput);\n                Console.Error.WriteLine(\"[StartInternal]: Exception: \" + ex);\n                throw;\n            }\n        }\n\n        private void Process_Exited(object sender, EventArgs e)\n        {\n            this.TransitionState(LifetimeState.Stopped);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Services/ElectronProcess/ElectronProcessBase.cs",
    "content": "﻿namespace ElectronNET.Runtime.Services.ElectronProcess\n{\n    using System.ComponentModel;\n\n    /// <summary>\n    /// Manages the Electron app process.\n    /// </summary>\n    [Localizable(false)]\n    internal abstract class ElectronProcessBase : LifetimeServiceBase\n    {\n        protected ElectronProcessBase()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Services/ElectronProcess/ElectronProcessPassive.cs",
    "content": "﻿namespace ElectronNET.Runtime.Services.ElectronProcess\n{\n    using ElectronNET.Runtime.Data;\n    using System;\n    using System.ComponentModel;\n    using System.Diagnostics;\n    using System.Threading.Tasks;\n\n    /// <summary>\n    /// Launches and manages the Electron app process.\n    /// </summary>\n    [Localizable(false)]\n    internal class ElectronProcessPassive : ElectronProcessBase\n    {\n        private readonly int pid;\n        private Process process;\n\n        /// <summary>Initializes a new instance of the <see cref=\"ElectronProcessPassive\"/> class.</summary>\n        /// <param name=\"pid\"></param>\n        public ElectronProcessPassive(int pid)\n        {\n            this.pid = pid;\n        }\n\n        protected override Task StartCore()\n        {\n            this.process = Process.GetProcessById(this.pid);\n\n            if (this.process == null)\n            {\n                throw new ArgumentException($\"Unable to find process with ID {this.pid}\");\n            }\n\n            this.process.Exited += this.Process_Exited1;\n\n            Task.Run(() => this.TransitionState(LifetimeState.Ready));\n\n            return Task.CompletedTask;\n        }\n\n        private void Process_Exited1(object sender, EventArgs e)\n        {\n            this.TransitionState(LifetimeState.Stopped);\n        }\n\n        protected override Task StopCore()\n        {\n            // Not sure about this:\n            ////this.process.Kill(true);\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Services/LifetimeServiceBase.cs",
    "content": "﻿namespace ElectronNET.Runtime.Services\n{\n    using ElectronNET.Runtime.Data;\n    using System;\n    using System.Runtime.CompilerServices;\n    using System.Threading.Tasks;\n\n    public abstract class LifetimeServiceBase\n    {\n        private readonly TaskCompletionSource tcsStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n        private readonly TaskCompletionSource tcsReady = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n        private readonly TaskCompletionSource tcsStopping = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n        private readonly TaskCompletionSource tcsStopped = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n\n        private LifetimeState state = LifetimeState.Uninitialized;\n\n        protected LifetimeServiceBase()\n        {\n        }\n\n        public event EventHandler Starting;\n\n        public event EventHandler Started;\n\n        public event EventHandler Ready;\n\n        public event EventHandler Stopping;\n\n        public event EventHandler Stopped;\n\n\n        public LifetimeState State => this.state;\n\n        public Task WaitStartedTask => this.tcsStarted.Task;\n\n        public Task WaitReadyTask => this.tcsReady.Task;\n\n        public Task WaitStoppingTask => this.tcsStopping.Task;\n\n        public Task WaitStoppedTask => this.tcsStopped.Task;\n\n\n        public virtual async Task Start()\n        {\n            this.ValidateMaxState(LifetimeState.Uninitialized);\n\n            await this.StartCore().ConfigureAwait(false);\n\n            this.TransitionState(LifetimeState.Starting);\n        }\n\n        public virtual async Task Stop()\n        {\n            this.ValidateMaxState(LifetimeState.Ready);\n\n            await this.StopCore().ConfigureAwait(false);\n\n            this.TransitionState(LifetimeState.Stopping);\n        }\n\n        protected virtual Task StopCore()\n        {\n            return Task.CompletedTask;\n        }\n\n        protected virtual Task StartCore()\n        {\n            return Task.CompletedTask;\n        }\n\n        private void ValidateMaxState(LifetimeState evalState, [CallerMemberName] string callerMemberName = null)\n        {\n            if (this.state > evalState)\n            {\n                throw new Exception($\"Invalid state! Cannot execute {callerMemberName} in state {this.state}\");\n            }\n        }\n\n        protected void TransitionState(LifetimeState newState)\n        {\n            if (newState == this.state)\n            {\n                return;\n            }\n\n            if (newState < this.state)\n            {\n                throw new Exception($\"Invalid state transition from {this.state} to {newState}: \" + this.GetType().Name);\n            }\n\n            var oldState = this.state;\n\n            this.state = newState;\n\n            switch (this.state)\n            {\n                case LifetimeState.Starting:\n                    this.Starting?.Invoke(this, EventArgs.Empty);\n                    break;\n                case LifetimeState.Started:\n                    this.Started?.Invoke(this, EventArgs.Empty);\n                    break;\n                case LifetimeState.Ready:\n                    this.Ready?.Invoke(this, EventArgs.Empty);\n                    break;\n                case LifetimeState.Stopping:\n                    this.Stopping?.Invoke(this, EventArgs.Empty);\n                    break;\n                case LifetimeState.Stopped:\n                    this.Stopped?.Invoke(this, EventArgs.Empty);\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException();\n            }\n\n            if (oldState < LifetimeState.Started && newState >= LifetimeState.Started)\n            {\n                this.tcsStarted.TrySetResult();\n            }\n\n            if (oldState < LifetimeState.Ready && newState >= LifetimeState.Ready)\n            {\n                this.tcsReady.TrySetResult();\n            }\n\n            if (oldState < LifetimeState.Stopping && newState >= LifetimeState.Stopping)\n            {\n                this.tcsStopping.TrySetResult();\n            }\n\n            if (oldState < LifetimeState.Stopped && newState >= LifetimeState.Stopped)\n            {\n                this.tcsStopped.TrySetResult();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/Services/SocketBridge/SocketBridgeService.cs",
    "content": "﻿namespace ElectronNET.Runtime.Services.SocketBridge\n{\n    using ElectronNET.API;\n    using ElectronNET.Runtime.Data;\n    using System;\n    using System.Threading.Tasks;\n\n    internal class SocketBridgeService : LifetimeServiceBase\n    {\n        private readonly int socketPort;\n        private readonly string socketUrl;\n        private SocketIoFacade socket;\n\n        public SocketBridgeService(int socketPort)\n        {\n            this.socketPort = socketPort;\n            this.socketUrl = $\"http://localhost:{this.socketPort}\";\n        }\n\n        public int SocketPort => this.socketPort;\n\n        internal SocketIoFacade Socket => this.socket;\n\n        protected override Task StartCore()\n        {\n            this.socket = new SocketIoFacade(this.socketUrl);\n            this.socket.BridgeConnected += this.Socket_BridgeConnected;\n            this.socket.BridgeDisconnected += this.Socket_BridgeDisconnected;\n            Task.Run(this.Connect);\n\n            return Task.CompletedTask;\n        }\n\n        protected override Task StopCore()\n        {\n            this.socket.Dispose();\n            return Task.CompletedTask;\n        }\n\n        private void Connect()\n        {\n            this.socket.Connect();\n            if (this.State < LifetimeState.Started)\n            {\n                this.TransitionState(LifetimeState.Started);\n            }\n        }\n\n        private void Socket_BridgeDisconnected(object sender, EventArgs e)\n        {\n            this.TransitionState(LifetimeState.Stopped);\n        }\n\n        private void Socket_BridgeConnected(object sender, EventArgs e)\n        {\n            this.TransitionState(LifetimeState.Ready);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Runtime/StartupManager.cs",
    "content": "﻿namespace ElectronNET.Runtime\n{\n    using System;\n    using System.Collections.Immutable;\n    using System.Globalization;\n    using System.Linq;\n    using System.Reflection;\n    using ElectronNET.Runtime.Controllers;\n    using ElectronNET.Runtime.Data;\n    using ElectronNET.Runtime.Helpers;\n\n    internal class StartupManager\n    {\n        public void Initialize()\n        {\n            try\n            {\n                ElectronNetRuntime.BuildInfo = this.GatherBuildInfo();\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine(ex);\n            }\n\n            this.CollectProcessData();\n            this.SetElectronExecutable();\n\n\n            ElectronNetRuntime.StartupMethod = this.DetectAppTypeAndStartup();\n            Console.WriteLine((string)(\"Evaluated StartupMethod: \" + ElectronNetRuntime.StartupMethod));\n\n            if (ElectronNetRuntime.DotnetAppType != DotnetAppType.AspNetCoreApp)\n            {\n                ElectronNetRuntime.RuntimeControllerCore = this.CreateRuntimeController();\n            }\n        }\n\n        private RuntimeControllerBase CreateRuntimeController()\n        {\n            switch (ElectronNetRuntime.StartupMethod)\n            {\n                case StartupMethod.PackagedDotnetFirst:\n                case StartupMethod.UnpackedDotnetFirst:\n                    return new RuntimeControllerDotNetFirst();\n                case StartupMethod.PackagedElectronFirst:\n                case StartupMethod.UnpackedElectronFirst:\n                    return new RuntimeControllerElectronFirst();\n                default:\n                    throw new ArgumentOutOfRangeException();\n            }\n        }\n\n        private StartupMethod DetectAppTypeAndStartup()\n        {\n            var isLaunchedByDotNet = LaunchOrderDetector.CheckIsLaunchedByDotNet();\n            var isUnPackaged = UnpackagedDetector.CheckIsUnpackaged();\n\n            if (isLaunchedByDotNet)\n            {\n                if (isUnPackaged)\n                {\n                    return StartupMethod.UnpackedDotnetFirst;\n                }\n\n                return StartupMethod.PackagedDotnetFirst;\n            }\n            else\n            {\n                if (isUnPackaged)\n                {\n                    return StartupMethod.UnpackedElectronFirst;\n                }\n\n                return StartupMethod.PackagedElectronFirst;\n            }\n        }\n\n        private void CollectProcessData()\n        {\n            var argsList = Environment.GetCommandLineArgs().ToImmutableList();\n\n            ElectronNetRuntime.ProcessArguments = argsList;\n\n            var portArg = argsList.FirstOrDefault(e => e.Contains(ElectronNetRuntime.ElectronPortArgumentName, StringComparison.OrdinalIgnoreCase));\n\n            if (portArg != null)\n            {\n                var parts = portArg.Split('=', StringSplitOptions.TrimEntries);\n                if (parts.Length > 1 && int.TryParse(parts[1], NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var result))\n                {\n                    ElectronNetRuntime.ElectronSocketPort = result;\n\n                    Console.WriteLine(\"Use Electron Port: \" + result);\n                }\n            }\n\n            var pidArg = argsList.FirstOrDefault(e => e.Contains(ElectronNetRuntime.ElectronPidArgumentName, StringComparison.OrdinalIgnoreCase));\n\n            if (pidArg != null)\n            {\n                var parts = pidArg.Split('=', StringSplitOptions.TrimEntries);\n                if (parts.Length > 1 && int.TryParse(parts[1], NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var result))\n                {\n                    ElectronNetRuntime.ElectronProcessId = result;\n\n                    Console.WriteLine(\"Electron Process ID: \" + result);\n                }\n            }\n        }\n\n        private void SetElectronExecutable()\n        {\n            string executable = ElectronNetRuntime.BuildInfo.ElectronExecutable;\n            if (string.IsNullOrEmpty(executable))\n            {\n                throw new Exception(\"AssemblyMetadataAttribute 'ElectronExecutable' could not be found!\");\n            }\n\n            if (Environment.OSVersion.Platform == PlatformID.Win32NT)\n            {\n                executable += \".exe\";\n            }\n\n            ElectronNetRuntime.ElectronExecutable = executable;\n        }\n\n        private BuildInfo GatherBuildInfo()\n        {\n            var buildInfo = new BuildInfo();\n\n            var electronAssembly = Assembly.GetEntryAssembly();\n\n            if (electronAssembly == null)\n            {\n                Console.WriteLine(\"GatherBuildInfo: Early exit\");\n                return buildInfo;\n            }\n\n            if (electronAssembly.GetName().Name == \"testhost\" || electronAssembly.GetName().Name == \"ReSharperTestRunner\")\n            {\n                Console.WriteLine(\"GatherBuildInfo: Detected testhost\");\n                electronAssembly = AppDomain.CurrentDomain.GetData(\"ElectronTestAssembly\") as Assembly ?? electronAssembly;\n            }\n            else\n            {\n                Console.WriteLine(\"GatherBuildInfo: No testhost detected: \" + electronAssembly.GetName().Name);\n            }\n\n            var attributes = electronAssembly.GetCustomAttributes<AssemblyMetadataAttribute>().ToList();\n\n            if (attributes.Count > 0)\n            {\n                buildInfo.ElectronExecutable = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.ElectronExecutable))?.Value;\n                buildInfo.ElectronVersion = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.ElectronVersion))?.Value;\n                buildInfo.RuntimeIdentifier = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.RuntimeIdentifier))?.Value;\n                buildInfo.Title = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.Title))?.Value;\n                buildInfo.Version = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.Version))?.Value;\n                buildInfo.BuildConfiguration = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.BuildConfiguration))?.Value;\n                var isAspNet = attributes.FirstOrDefault(e => e.Key == \"IsAspNet\")?.Value;\n                var isSingleInstance = attributes.FirstOrDefault(e => e.Key == nameof(buildInfo.ElectronSingleInstance))?.Value;\n                var httpPort = attributes.FirstOrDefault(e => e.Key == \"AspNetHttpPort\")?.Value;\n\n                if (isAspNet?.Length > 0 && bool.TryParse(isAspNet, out var isAspNetActive) && isAspNetActive)\n                {\n                    ElectronNetRuntime.DotnetAppType = DotnetAppType.AspNetCoreApp;\n                }\n\n                if (bool.TryParse(isSingleInstance, out var parsedBool))\n                {\n                    buildInfo.ElectronSingleInstance = parsedBool;\n                }\n\n                if (httpPort?.Length > 0 && int.TryParse(httpPort, out var port))\n                {\n                    ElectronNetRuntime.AspNetWebPort = port;\n                }\n            }\n\n            return buildInfo;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Serialization/ElectronJson.cs",
    "content": "using ElectronNET.API.Entities;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace ElectronNET.API.Serialization\n{\n    internal static class ElectronJson\n    {\n        public static readonly JsonSerializerOptions Options = new JsonSerializerOptions\n        {\n            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,\n            WriteIndented = false,\n            Converters =\n            {\n                new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)\n            }\n        };\n    }\n\n    // Use source generation where feasible for hot paths\n    [JsonSourceGenerationOptions(WriteIndented = false, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]\n    [JsonSerializable(typeof(TrayClickEventArgs))]\n    [JsonSerializable(typeof(Rectangle))]\n    [JsonSerializable(typeof(Display))]\n    [JsonSerializable(typeof(UpdateInfo))]\n    [JsonSerializable(typeof(ProgressInfo))]\n    [JsonSerializable(typeof(UpdateCheckResult))]\n    [JsonSerializable(typeof(SemVer))]\n    internal partial class ElectronJsonContext : JsonSerializerContext\n    {\n    }\n}"
  },
  {
    "path": "src/ElectronNET.API/Serialization/JsonToBoxedPrimitivesConverter.cs",
    "content": "﻿namespace ElectronNET.Serialization\n{\n    using System;\n    using System.Collections.Generic;\n    using System.Text.Json;\n    using System.Text.Json.Serialization;\n\n    public sealed class JsonToBoxedPrimitivesConverter : JsonConverter<object>\n    {\n        public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n        {\n            return ReadValue(ref reader);\n        }\n\n        private static object ReadValue(ref Utf8JsonReader r)\n        {\n            switch (r.TokenType)\n            {\n                case JsonTokenType.StartObject:\n\n                    var obj = new Dictionary<string, object>();\n                    while (r.Read())\n                    {\n                        if (r.TokenType == JsonTokenType.EndObject)\n                        {\n                            return obj;\n                        }\n\n                        if (r.TokenType != JsonTokenType.PropertyName)\n                        {\n                            throw new JsonException(\"Expected property name.\");\n                        }\n\n                        string name = r.GetString()!;\n                        if (!r.Read())\n                        {\n                            throw new JsonException(\"Unexpected end while reading property value.\");\n                        }\n\n                        obj[name] = ReadValue(ref r);\n                    }\n\n                    throw new JsonException(\"Unexpected end while reading object.\");\n\n                case JsonTokenType.StartArray:\n\n                    var list = new List<object>();\n                    while (r.Read())\n                    {\n                        if (r.TokenType == JsonTokenType.EndArray)\n                        {\n                            return list;\n                        }\n\n                        list.Add(ReadValue(ref r));\n                    }\n\n                    throw new JsonException(\"Unexpected end while reading array.\");\n\n                case JsonTokenType.True: return true;\n                case JsonTokenType.False: return false;\n                case JsonTokenType.Null: return null;\n\n                case JsonTokenType.Number:\n\n                    if (r.TryGetInt32(out int i))\n                    {\n                        return i;\n                    }\n\n                    if (r.TryGetInt64(out long l))\n                    {\n                        return l;\n                    }\n\n                    if (r.TryGetDouble(out double d))\n                    {\n                        return d;\n                    }\n\n                    return r.GetDecimal();\n\n                case JsonTokenType.String:\n\n                    string s = r.GetString()!;\n\n                    if (DateTimeOffset.TryParse(s, out var dto))\n                    {\n                        return dto;\n                    }\n\n                    if (DateTime.TryParse(s, out var dt))\n                    {\n                        return dt;\n                    }\n\n                    if (TimeSpan.TryParse(s, out var ts))\n                    {\n                        return ts;\n                    }\n\n                    if (Guid.TryParse(s, out var g))\n                    {\n                        return g;\n                    }\n\n                    return s;\n\n                default:\n                    throw new JsonException($\"Unsupported token {r.TokenType}\");\n            }\n        }\n\n        public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)\n        {\n            if (value is null)\n            {\n                writer.WriteNullValue();\n                return;\n            }\n\n            writer.WriteStartObject();\n            writer.WriteEndObject();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.AspNet/API/ServiceCollectionExtensions.cs",
    "content": "﻿namespace ElectronNET.API\n{\n    using Microsoft.Extensions.DependencyInjection;\n\n    /// <summary>\n    /// \n    /// </summary>\n    public static class ServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Adds the <see cref=\"Electron\"/> Members to the Service Collection\n        /// </summary>\n        public static IServiceCollection AddElectron(this IServiceCollection services)\n            => services\n                // adding in this manner to ensure late binding.\n                .AddSingleton(_ => IpcMain.Instance)\n                .AddSingleton(_ => App.Instance)\n                .AddSingleton(_ => AutoUpdater.Instance)\n                .AddSingleton(_ => WindowManager.Instance)\n                .AddSingleton(_ => Menu.Instance)\n                .AddSingleton(_ => Dialog.Instance)\n                .AddSingleton(_ => Notification.Instance)\n                .AddSingleton(_ => Tray.Instance)\n                .AddSingleton(_ => GlobalShortcut.Instance)\n                .AddSingleton(_ => Shell.Instance)\n                .AddSingleton(_ => Screen.Instance)\n                .AddSingleton(_ => Clipboard.Instance)\n                .AddSingleton(_ => HostHook.Instance)\n                .AddSingleton(_ => PowerMonitor.Instance)\n                .AddSingleton(_ => NativeTheme.Instance)\n                .AddSingleton(_ => Dock.Instance);\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs",
    "content": "﻿namespace ElectronNET.API\n{\n    using System;\n    using System.Threading.Tasks;\n    using Microsoft.AspNetCore.Builder;\n\n    /// <summary>\n    /// Provides extension methods for <see cref=\"WebApplicationBuilder\"/> to enable Electron.NET\n    /// integration in ASP.NET Core applications (including Razor Pages) using the minimal hosting model.\n    /// </summary>\n    /// <remarks>\n    /// Call this extension during host configuration (for example, in Program.cs) to wire up Electron\n    /// with any command-line arguments and an optional application-ready callback.\n    /// </remarks>\n    public static class WebApplicationBuilderExtensions\n    {\n        /// <summary>\n        /// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback.\n        /// </summary>\n        /// <param name=\"builder\">The <see cref=\"WebApplicationBuilder\"/> to extend.</param>\n        /// <param name=\"args\">The command-line arguments passed to the process, forwarded to Electron.</param>\n        /// <param name=\"onAppReadyCallback\">\n        /// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.\n        /// </param>\n        /// <returns>\n        /// The same <see cref=\"WebApplicationBuilder\"/> instance to enable fluent configuration.\n        /// </returns>\n        /// <example>\n        /// <code language=\"csharp\">\n        /// var builder = WebApplication.CreateBuilder(args)\n        ///     .UseElectron(args, async () =>\n        ///     {\n        ///         // Create the main browser window or perform other startup tasks.\n        ///     });\n        ///\n        /// var app = builder.Build();\n        /// app.MapRazorPages();\n        /// app.Run();\n        /// </code>\n        /// </example>\n        public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func<Task> onAppReadyCallback)\n        {\n            builder.WebHost.UseElectron(args, onAppReadyCallback);\n\n            return builder;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs",
    "content": "﻿namespace ElectronNET.API\n{\n    using System;\n    using System.IO;\n    using System.Threading.Tasks;\n    using ElectronNET.AspNet;\n    using ElectronNET.AspNet.Runtime;\n    using ElectronNET.Runtime;\n    using ElectronNET.Runtime.Data;\n    using ElectronNET.Runtime.Helpers;\n    using Microsoft.AspNetCore.Hosting;\n    using Microsoft.Extensions.DependencyInjection;\n\n    /// <summary>\n    /// Provides extension methods for <see cref=\"IWebHostBuilder\"/> to enable Electron.NET\n    /// integration in ASP.NET Core applications (including Razor Pages) using the WebHost-based hosting model.\n    /// </summary>\n    /// <remarks>\n    /// Call this extension during web host configuration (for example, inside <c>ConfigureWebHostDefaults</c> in Program.cs)\n    /// to wire up Electron with any command-line arguments and an optional application-ready callback.\n    /// </remarks>\n    public static class WebHostBuilderExtensions\n    {\n        /// <summary>\n        /// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback.\n        /// </summary>\n        /// <param name=\"builder\">The <see cref=\"IWebHostBuilder\"/> to extend.</param>\n        /// <param name=\"args\">The command-line arguments passed to the process.</param>\n        /// <param name=\"onAppReadyCallback\">\n        /// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.\n        /// </param>\n        /// <returns>\n        /// The same <see cref=\"IWebHostBuilder\"/> instance to enable fluent configuration.\n        /// </returns>\n        /// <example>\n        /// <code language=\"csharp\">\n        /// using Microsoft.AspNetCore.Hosting;\n        /// using Microsoft.Extensions.Hosting;\n        /// using ElectronNET.API;\n        ///\n        /// public class Program\n        /// {\n        ///     public static void Main(string[] args)\n        ///     {\n        ///         Host.CreateDefaultBuilder(args)\n        ///             .ConfigureWebHostDefaults(webBuilder =>\n        ///             {\n        ///                 webBuilder.UseStartup&lt;Startup&gt;();\n        ///                 webBuilder.UseElectron(args, async () =>\n        ///                 {\n        ///                     // Create the main browser window or perform other startup tasks.\n        ///                 });\n        ///             })\n        ///             .Build()\n        ///             .Run();\n        ///     }\n        /// }\n        /// </code>\n        /// </example>\n        public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func<Task> onAppReadyCallback)\n        {\n            ElectronNetRuntime.OnAppReadyCallback = onAppReadyCallback;\n\n            // no matter how this is set - let's unset to prevent Electron not starting as expected\n            // e.g., VS Code sets this env variable, but this will cause `require(\"electron\")` to not\n            // work as expected, see issue #952\n            Environment.SetEnvironmentVariable(\"ELECTRON_RUN_AS_NODE\", null);\n\n            var webPort = PortHelper.GetFreePort(ElectronNetRuntime.AspNetWebPort ?? ElectronNetRuntime.DefaultWebPort);\n            ElectronNetRuntime.AspNetWebPort = webPort;\n\n            // check for the content folder if its exists in base director otherwise no need to include\n            // It was used before because we are publishing the project which copies everything to bin folder and contentroot wwwroot was folder there.\n            // now we have implemented the live reload if app is run using /watch then we need to use the default project path.\n            if (Directory.Exists($\"{AppDomain.CurrentDomain.BaseDirectory}\\\\wwwroot\"))\n            {\n                builder = builder.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)\n                    .UseUrls(\"http://localhost:\" + webPort);\n            }\n            else\n            {\n                builder = builder.UseUrls(\"http://localhost:\" + webPort);\n            }\n\n            builder = builder.ConfigureServices(services =>\n            {\n                services.AddTransient<IStartupFilter, ServerReadyStartupFilter>();\n                services.AddSingleton<AspNetLifetimeAdapter>();\n\n                switch (ElectronNetRuntime.StartupMethod)\n                {\n                    case StartupMethod.PackagedElectronFirst:\n                    case StartupMethod.UnpackedElectronFirst:\n                        services.AddSingleton<IElectronNetRuntimeController, RuntimeControllerAspNetElectronFirst>();\n                        break;\n                    case StartupMethod.PackagedDotnetFirst:\n                    case StartupMethod.UnpackedDotnetFirst:\n                        services.AddSingleton<IElectronNetRuntimeController, RuntimeControllerAspNetDotnetFirst>();\n                        break;\n                    default:\n                        throw new ArgumentOutOfRangeException();\n                }\n            });\n\n            return builder;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.AspNet/ElectronNET.AspNet.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"..\\common.props\" />\n\n  <PropertyGroup>\n    <TargetFrameworks>net6.0;net8.0;net10.0</TargetFrameworks>\n    <PackageOutputPath>..\\..\\artifacts</PackageOutputPath>\n    <PackageId>$(PackageNamePrefix).AspNet</PackageId>\n    <Title>$(PackageId)</Title>\n    <Description>$(DescriptionFirstPart) This package contains the ASP.Net Core integration.</Description>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <IncludeSymbols>True</IncludeSymbols>\n    <SymbolPackageFormat>snupkg</SymbolPackageFormat>\n    <Nullable>disable</Nullable>\n    <RootNamespace>ElectronNET</RootNamespace>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0|AnyCPU'\">\n    <NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'\">\n    <NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net10.0|AnyCPU'\">\n    <NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'\">\n    <NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'\">\n    <NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net10.0|AnyCPU'\">\n    <NoWarn>1701;1702;4014;CS4014;CA1416;CS1591</NoWarn>\n  </PropertyGroup>\n  <ItemGroup>\n    <FrameworkReference Include=\"Microsoft.AspNetCore.App\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"PackageIcon.png\" Pack=\"true\" PackagePath=\"\\\" />\n    <None Include=\"../../README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.SourceLink.GitHub\" Version=\"8.0.0\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ElectronNET.API\\ElectronNET.API.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs",
    "content": "﻿namespace ElectronNET.AspNet.Runtime\n{\n    using System;\n    using System.Threading.Tasks;\n    using ElectronNET.API;\n    using ElectronNET.Common;\n    using ElectronNET.Runtime.Controllers;\n    using ElectronNET.Runtime.Data;\n    using ElectronNET.Runtime.Services.SocketBridge;\n\n    internal abstract class RuntimeControllerAspNetBase : RuntimeControllerBase\n    {\n        private readonly AspNetLifetimeAdapter aspNetLifetimeAdapter;\n        private SocketBridgeService socketBridge;\n\n        protected RuntimeControllerAspNetBase(AspNetLifetimeAdapter aspNetLifetimeAdapter)\n        {\n            this.aspNetLifetimeAdapter = aspNetLifetimeAdapter;\n            this.aspNetLifetimeAdapter.Ready += this.AspNetLifetimeAdapter_Ready;\n            this.aspNetLifetimeAdapter.Stopping += this.AspNetLifetimeAdapter_Stopping;\n            this.aspNetLifetimeAdapter.Stopped += this.AspNetLifetimeAdapter_Stopped;\n\n            ElectronNetRuntime.RuntimeControllerCore = this;\n        }\n\n        internal override SocketBridgeService SocketBridge => this.socketBridge;\n\n        internal override SocketIoFacade Socket\n        {\n            get\n            {\n                if (this.State == LifetimeState.Ready)\n                {\n                    return this.socketBridge.Socket;\n                }\n\n                throw new Exception(\"Cannot access socket bridge. Runtime is not in 'Ready' state\");\n            }\n        }\n\n        protected void CreateSocketBridge(int port)\n        {\n            this.socketBridge = new SocketBridgeService(port);\n            this.socketBridge.Ready += this.SocketBridge_Ready;\n            this.socketBridge.Stopped += this.SocketBridge_Stopped;\n            this.socketBridge.Start();\n        }\n\n        protected void HandleReady()\n        {\n            if (this.SocketBridge.IsReady() &&\n                this.ElectronProcess.IsReady() &&\n                this.aspNetLifetimeAdapter.IsReady())\n            {\n                this.TransitionState(LifetimeState.Ready);\n                Task.Run(this.RunReadyCallback);\n            }\n        }\n\n        protected void HandleStopped()\n        {\n            this.TransitionState(LifetimeState.Stopping);\n\n            if (this.SocketBridge.IsNotStopped())\n            {\n                this.SocketBridge.Stop();\n            }\n\n            if (this.ElectronProcess.IsNotStopped())\n            {\n                this.ElectronProcess.Stop();\n            }\n\n            if (this.aspNetLifetimeAdapter.IsNotStopped())\n            {\n                this.aspNetLifetimeAdapter.Stop();\n            }\n\n            if ((this.SocketBridge.IsNullOrStopped()) &&\n                (this.ElectronProcess.IsNullOrStopped()) &&\n                (this.aspNetLifetimeAdapter.IsNullOrStopped()))\n            {\n                this.TransitionState(LifetimeState.Stopped);\n            }\n        }\n\n        protected abstract override Task StopCore();\n\n        private void SocketBridge_Ready(object sender, EventArgs e)\n        {\n            this.HandleReady();\n        }\n\n        private void AspNetLifetimeAdapter_Ready(object sender, EventArgs e)\n        {\n            this.HandleReady();\n        }\n\n        private void SocketBridge_Stopped(object sender, EventArgs e)\n        {\n            this.HandleStopped();\n        }\n\n        private void AspNetLifetimeAdapter_Stopped(object sender, EventArgs e)\n        {\n            this.HandleStopped();\n        }\n\n        private void AspNetLifetimeAdapter_Stopping(object sender, EventArgs e)\n        {\n        }\n\n        private async Task RunReadyCallback()\n        {\n            if (ElectronNetRuntime.OnAppReadyCallback == null)\n            {\n                Console.WriteLine(\"Warning: Non OnReadyCallback provided in UseElectron() setup.\");\n                return;\n            }\n\n            try\n            {\n                await ElectronNetRuntime.OnAppReadyCallback().ConfigureAwait(false);\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine(\"Exception while executing OnAppReadyCallback. Stopping...\\n\" + ex);\n                this.Stop();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirst.cs",
    "content": "﻿namespace ElectronNET.AspNet.Runtime\n{\n    using System;\n    using System.Threading.Tasks;\n    using ElectronNET.Common;\n    using ElectronNET.Runtime.Data;\n    using ElectronNET.Runtime.Helpers;\n    using ElectronNET.Runtime.Services.ElectronProcess;\n\n    internal class RuntimeControllerAspNetDotnetFirst : RuntimeControllerAspNetBase\n    {\n        private ElectronProcessBase electronProcess;\n        private int? port;\n\n        public RuntimeControllerAspNetDotnetFirst(AspNetLifetimeAdapter aspNetLifetimeAdapter) : base(aspNetLifetimeAdapter)\n        {\n        }\n\n        internal override ElectronProcessBase ElectronProcess => this.electronProcess;\n\n        protected override Task StartCore()\n        {\n            var isUnPacked = ElectronNetRuntime.StartupMethod.IsUnpackaged();\n            var electronBinaryName = ElectronNetRuntime.ElectronExecutable;\n            var args = Environment.CommandLine;\n            this.port = ElectronNetRuntime.ElectronSocketPort;\n\n            if (!this.port.HasValue)\n            {\n                this.port = PortHelper.GetFreePort(ElectronNetRuntime.DefaultSocketPort);\n                ElectronNetRuntime.ElectronSocketPort = this.port;\n            }\n\n            this.electronProcess = new ElectronProcessActive(isUnPacked, electronBinaryName, args, this.port.Value);\n            this.electronProcess.Ready += this.ElectronProcess_Ready;\n            this.electronProcess.Stopped += this.ElectronProcess_Stopped;\n\n            return this.electronProcess.Start();\n        }\n\n        protected override Task StopCore()\n        {\n            this.electronProcess.Stop();\n            return Task.CompletedTask;\n        }\n\n        private void ElectronProcess_Ready(object sender, EventArgs e)\n        {\n            this.TransitionState(LifetimeState.Started);\n            this.CreateSocketBridge(this.port!.Value);\n        }\n\n        private void ElectronProcess_Stopped(object sender, EventArgs e)\n        {\n            this.HandleStopped();\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetElectronFirst.cs",
    "content": "﻿namespace ElectronNET.AspNet.Runtime\n{\n    using System;\n    using System.Threading.Tasks;\n    using ElectronNET.Runtime.Data;\n    using ElectronNET.Runtime.Services.ElectronProcess;\n\n    internal class RuntimeControllerAspNetElectronFirst : RuntimeControllerAspNetBase\n    {\n        private ElectronProcessBase electronProcess;\n        private int? port;\n\n        public RuntimeControllerAspNetElectronFirst(AspNetLifetimeAdapter aspNetLifetimeAdapter) : base(aspNetLifetimeAdapter)\n        {\n        }\n\n        internal override ElectronProcessBase ElectronProcess => this.electronProcess;\n\n        protected override Task StartCore()\n        {\n            this.port = ElectronNetRuntime.ElectronSocketPort;\n\n            if (!this.port.HasValue)\n            {\n                throw new Exception(\"No port has been specified by Electron!\");\n            }\n\n            if (!ElectronNetRuntime.ElectronProcessId.HasValue)\n            {\n                throw new Exception(\"No electronPID has been specified by Electron!\");\n            }\n\n            this.CreateSocketBridge(this.port!.Value);\n\n            this.electronProcess = new ElectronProcessPassive(ElectronNetRuntime.ElectronProcessId.Value);\n            this.electronProcess.Stopped += this.ElectronProcess_Stopped;\n\n            this.electronProcess.Start();\n\n            Task.Run(() => this.TransitionState(LifetimeState.Started));\n\n            return Task.CompletedTask;\n        }\n\n        protected override Task StopCore()\n        {\n            this.electronProcess.Stop();\n            return Task.CompletedTask;\n        }\n\n        private void ElectronProcess_Stopped(object sender, EventArgs e)\n        {\n            this.HandleStopped();\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.AspNet/Runtime/Helpers/ServerReadyStartupFilter.cs",
    "content": "﻿namespace ElectronNET.AspNet\n{\n    using System;\n    using ElectronNET.AspNet.Runtime;\n    using ElectronNET.Runtime;\n    using Microsoft.AspNetCore.Builder;\n    using Microsoft.AspNetCore.Hosting;\n    using Microsoft.Extensions.DependencyInjection;\n\n    internal sealed class ServerReadyStartupFilter : IStartupFilter\n    {\n        /// <summary>\n        /// Extends the provided <paramref name=\"next\" /> and returns an <see cref=\"T:System.Action\" /> of the same type.\n        /// </summary>\n        /// <param name=\"next\">The Configure method to extend.</param>\n        /// <returns>A modified <see cref=\"T:System.Action\" />.</returns>\n        public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)\n        {\n            return app =>\n            {\n                _ = app.ApplicationServices.GetService<AspNetLifetimeAdapter>();\n                var runtimeController = app.ApplicationServices.GetService<IElectronNetRuntimeController>();\n\n                runtimeController.Start();\n\n                next(app);\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.AspNet/Runtime/Services/AspNetLifetimeAdapter.cs",
    "content": "﻿namespace ElectronNET.AspNet.Runtime\n{\n    using System.Threading.Tasks;\n    using ElectronNET.Runtime.Data;\n    using ElectronNET.Runtime.Services;\n    using Microsoft.Extensions.Hosting;\n\n    internal class AspNetLifetimeAdapter : LifetimeServiceBase\n    {\n        private readonly IHostApplicationLifetime lifetimeService;\n\n        public AspNetLifetimeAdapter(IHostApplicationLifetime lifetimeService)\n        {\n            this.lifetimeService = lifetimeService;\n\n            this.lifetimeService.ApplicationStarted.Register(() => this.TransitionState(LifetimeState.Ready));\n            this.lifetimeService.ApplicationStopping.Register(() => this.TransitionState(LifetimeState.Stopping));\n            this.lifetimeService.ApplicationStopped.Register(() => this.TransitionState(LifetimeState.Stopped));\n        }\n\n        protected override Task StopCore()\n        {\n            this.lifetimeService.StopApplication();\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.Build/ElectronNET.Build.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <Import Project=\"..\\common.props\" />\n\n    <PropertyGroup>\n        <TargetFramework>netstandard2.0</TargetFramework>\n        <IsPackable>False</IsPackable>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"Microsoft.Build.Utilities.Core\" Version=\"17.3.2\" />\n    </ItemGroup>\n\n\n\n    <PropertyGroup>\n\n        <_DllTargetPath>$(MSBuildThisFileDirectory)\\..\\ElectronNET\\build</_DllTargetPath>\n\n    </PropertyGroup>\n\n    <Target BeforeTargets=\"AfterBuild\" Name=\"CopyToBuildFolder\">\n\n        <ItemGroup>\n            <OutputFiles Include=\"$(OutDir)**\\*.dll\"></OutputFiles>\n        </ItemGroup>\n\n        <Message Text=\"Copy ElectronNET.Build.dll to destination: $(_DllTargetPath)\" Importance=\"high\"/>\n\n        <Copy SourceFiles=\"@(OutputFiles)\"\n              DestinationFolder=\"$(_DllTargetPath)\\%(RecursiveDir)\"\n              OverwriteReadOnlyFiles=\"true\"></Copy>\n\n    </Target>\n\n</Project>\n"
  },
  {
    "path": "src/ElectronNET.Build/ElectronNET.Build.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:String x:Key=\"/Default/CodeInspection/Daemon/ConfigureAwaitAnalysisMode/@EntryValue\">Library</s:String></wpf:ResourceDictionary>"
  },
  {
    "path": "src/ElectronNET.Build/PrintItemMetadata.cs",
    "content": "﻿namespace ElectronNET.Build\n{\n    using System;\n    using Microsoft.Build.Framework;\n    using Microsoft.Build.Utilities;\n\n    public class DumpItemMetadataTask : Task\n    {\n        // The item group whose metadata will be dumped.\n        [Required]\n        public ITaskItem[] Items { get; set; }\n\n        public override bool Execute()\n        {\n            try\n            {\n                foreach (var item in this.Items)\n                {\n                    // Log the item's identity (the Include attribute)\n                    this.Log.LogMessage(MessageImportance.High, $\"Item: {item.ItemSpec}\");\n\n                    // Iterate through each metadata field of the item.\n                    foreach (string metadataName in item.MetadataNames)\n                    {\n                        string metadataValue = item.GetMetadata(metadataName);\n                        this.Log.LogMessage(MessageImportance.High, $\"    {metadataName}: {metadataValue}\");\n                    }\n                }\n\n                return true;\n            }\n            catch (Exception ex)\n            {\n                this.Log.LogErrorFromException(ex);\n                return false;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.Build/RemoveEnvironmentVariables.cs",
    "content": "﻿namespace ElectronNET.Build\n{\n    using System;\n    using System.Collections.Generic;\n    using System.IO;\n    using System.Linq;\n    using System.Text.RegularExpressions;\n    using Microsoft.Build.Framework;\n    using Microsoft.Build.Utilities;\n\n    public class RemoveEnvironmentVariables : Task\n    {\n        [Required]\n        public string Variables { get; set; }\n\n        public override bool Execute()\n        {\n            try\n            {\n                if (string.IsNullOrEmpty(this.Variables))\n                {\n                    this.Log.LogError(\"The Variables property is not set\");\n                    return false;\n                }\n\n                var items = this.Variables.Split(new[] { ':', ';', ',' }, StringSplitOptions.RemoveEmptyEntries);\n                foreach (var item in items)\n                {\n                    Environment.SetEnvironmentVariable(item.Trim(), null);\n                    this.Log.LogMessage(\"Unset environment variable: {0}\", item);\n                }\n\n                return true;\n            }\n            catch (Exception ex)\n            {\n                this.Log.LogErrorFromException(ex);\n                return false;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.Build/ReplaceMsBuildPropertiesTask.cs",
    "content": "﻿namespace ElectronNET.Build\n{\n    using System;\n    using System.Collections.Generic;\n    using System.IO;\n    using System.Text.RegularExpressions;\n    using Microsoft.Build.Framework;\n    using Microsoft.Build.Utilities;\n\n    public class ReplaceTemplateTask : Task\n    {\n        [Required]\n        public string TemplateFile { get; set; }\n\n        [Required]\n        public string OutputFile { get; set; }\n\n        [Required]\n        public ITaskItem[] TemplateProperties { get; set; }\n\n        public override bool Execute()\n        {\n            try\n            {\n                ////var props = this.BuildEngine9.GetGlobalProperties();\n\n                ////var globalProperties = props\n                ////    .Select(e => string.Format(\"{0}: {1}\", e.Key, e.Value));\n\n                ////this.Log.LogMessage(MessageImportance.High, \"Global Properties: \\r\\n\" + string.Join(Environment.NewLine, globalProperties));\n\n                ////var envVariables = Environment.GetEnvironmentVariables();\n                ////var envList = new List<string>();\n                ////foreach (var v in envVariables.Keys)\n                ////{\n                ////    envList.Add(string.Format(\"{0}: {1}\", v, envVariables[v]));\n                ////}\n\n                ////this.Log.LogMessage(MessageImportance.High, \"Environment Variables: \\r\\n\" + string.Join(Environment.NewLine, envList));\n\n                string content = File.ReadAllText(this.TemplateFile);\n\n                // Build a dictionary of property names and values.\n                var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);\n                foreach (var item in this.TemplateProperties)\n                {\n                    dict[item.ItemSpec] = item.GetMetadata(\"Value\").Replace(\"\\\\\", \"\\\\\\\\\");\n                }\n\n                // Regex pattern to match placeholders like $(PropertyName)\n                string pattern = @\"\\$\\((?<prop>\\w+)\\)\";\n                content = Regex.Replace(content, pattern, match =>\n                {\n                    string propName = match.Groups[\"prop\"].Value;\n                    return dict.TryGetValue(propName, out var value) ? value : match.Value;\n                });\n\n                // Check if the output file exists and read its content\n                if (File.Exists(this.OutputFile))\n                {\n                    string existingContent = File.ReadAllText(this.OutputFile);\n                    // Only write the file if the content has changed\n                    if (existingContent != content)\n                    {\n                        File.WriteAllText(this.OutputFile, content);\n                    }\n                }\n                else\n                {\n                    // Write the transformed content to the output file if it doesn't exist\n                    File.WriteAllText(this.OutputFile, content);\n                }\n\n                return true;\n            }\n            catch (Exception ex)\n            {\n                this.Log.LogErrorFromException(ex);\n                return false;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.ConsoleApp/ElectronNET.ConsoleApp.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <!-- When this is enabled, the project will be switched from nuget packages to consuming the ElectronNet orchestration directly -->\n    <ElectronNetDevMode>true</ElectronNetDevMode>\n  </PropertyGroup>\n\n  <Import Project=\"..\\ElectronNET\\build\\ElectronNET.Core.props\" Condition=\"$(ElectronNetDevMode)\" />\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <OutputType>exe</OutputType>\n  </PropertyGroup>\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <ImportNuGetBuildTasksPackTargetsFromSdk>false</ImportNuGetBuildTasksPackTargetsFromSdk>\n    <PublishTrimmed>False</PublishTrimmed>\n    <NuGetAudit>false</NuGetAudit>\n    <Nullable>disable</Nullable>\n  </PropertyGroup>\n  <PropertyGroup Label=\"ElectronNetCommon\">\n    <PackageIcon>128.png</PackageIcon>\n    <ApplicationIcon>app.ico</ApplicationIcon>\n    <NoWin32Manifest>true</NoWin32Manifest>\n    <ElectronIcon>app.ico</ElectronIcon>\n    <Title>ElectronNET API Demo1</Title>\n    <Version>1.0.2</Version>\n    <Product>com.electronnet-apisamples.app</Product>\n    <Description>Electron.NET Demo Application</Description>\n    <Company>Electron.Net</Company>\n    <Copyright>Copyright © 2025, Electron.NET</Copyright>\n    <PackageTags>Electron;.NET;ASP;NET;Sample;App</PackageTags>\n    <ElectronVersion>30.4.0</ElectronVersion>\n    <ElectronSplashScreen></ElectronSplashScreen>\n    <License>MIT</License>\n    <TypeScriptModuleKind>commonjs</TypeScriptModuleKind>\n    <ElectronSingleInstance>false</ElectronSingleInstance>\n    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Remove=\"bin\\**\" />\n    <Compile Remove=\"publish\\**\" />\n    <Content Remove=\"publish\\**\" />\n    <EmbeddedResource Remove=\"bin\\**\" />\n    <EmbeddedResource Remove=\"publish\\**\" />\n    <None Remove=\"bin\\**\" />\n    <None Remove=\"publish\\**\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Update=\"Assets\\electron.ico\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"Assets\\electron_32x32.png\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Remove=\"obj\\**\" />\n    <Compile Remove=\"publish\\**\" />\n    <Content Remove=\"publish\\**\" />\n    <EmbeddedResource Remove=\"obj\\**\" />\n    <EmbeddedResource Remove=\"publish\\**\" />\n    <None Remove=\"obj\\**\" />\n    <None Remove=\"publish\\**\" />\n    <TypeScriptCompile Remove=\"bin\\**\" />\n    <TypeScriptCompile Remove=\"obj\\**\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ElectronNET.API\\ElectronNET.API.csproj\" Condition=\"$(ElectronNetDevMode)\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"ElectronNET.Core\" Version=\"0.4.1\" Condition=\"'$(ElectronNetDevMode)' != 'true'\" />\n  </ItemGroup>\n\n  <Import Project=\"..\\ElectronNET\\build\\ElectronNET.Core.targets\" Condition=\"$(ElectronNetDevMode)\" />\n\n</Project>"
  },
  {
    "path": "src/ElectronNET.ConsoleApp/Program.cs",
    "content": "﻿using ElectronNET.API;\n\nnamespace ElectronNET.WebApp\n{\n    using System;\n    using System.Threading.Tasks;\n    using ElectronNET.API.Entities;\n\n    public class Program\n    {\n        public static async Task Main(string[] args)\n        {\n            var runtimeController = ElectronNetRuntime.RuntimeController;\n\n            try\n            {\n                await runtimeController.Start();\n\n                await runtimeController.WaitReadyTask;\n\n                await ElectronBootstrap();\n\n                await runtimeController.WaitStoppedTask;\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine(ex);\n                await runtimeController.Stop().ConfigureAwait(false);\n\n                await runtimeController.WaitStoppedTask.WaitAsync(TimeSpan.FromSeconds(2)).ConfigureAwait(false);\n            }\n        }\n\n        public static async Task ElectronBootstrap()\n        {\n            //AddDevelopmentTests();\n\n            var browserWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions\n            {\n                Width = 1152,\n                Height = 940,\n                Show = false,\n            }, \"https://github.com/ElectronNET/Electron.NET\");\n\n            await browserWindow.WebContents.Session.ClearCacheAsync();\n\n            browserWindow.OnReadyToShow += () => browserWindow.Show();\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.ConsoleApp/Properties/PublishProfiles/linux-x64.pubxml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <PublishDir>publish\\Release\\net8.0\\linux-x64</PublishDir>\n    <PublishProtocol>FileSystem</PublishProtocol>\n    <_TargetId>Folder</_TargetId>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>\n    <SelfContained>false</SelfContained>\n    <PublishSingleFile>false</PublishSingleFile>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "src/ElectronNET.ConsoleApp/Properties/PublishProfiles/publish-win-x64.pubxml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nhttps://go.microsoft.com/fwlink/?LinkID=208121.\n-->\n<Project>\n  <PropertyGroup>\n    <DeleteExistingFiles>true</DeleteExistingFiles>\n    <ExcludeApp_Data>false</ExcludeApp_Data>\n    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>\n    <LastUsedPlatform>Any CPU</LastUsedPlatform>\n    <PublishProvider>FileSystem</PublishProvider>\n    <PublishUrl>publish\\Release\\net8.0\\win-x64\\</PublishUrl>\n    <WebPublishMethod>FileSystem</WebPublishMethod>\n    <_TargetId>Folder</_TargetId>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n    <SelfContained>true</SelfContained>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "src/ElectronNET.ConsoleApp/Properties/PublishProfiles/win-x64.pubxml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->\n<Project>\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <PublishDir>publish\\Release\\net8.0\\win-x64</PublishDir>\n    <PublishProtocol>FileSystem</PublishProtocol>\n    <_TargetId>Folder</_TargetId>\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n    <SelfContained>false</SelfContained>\n    <PublishSingleFile>false</PublishSingleFile>\n    <PublishReadyToRun>false</PublishReadyToRun>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "src/ElectronNET.ConsoleApp/Properties/electron-builder.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/electron-userland/electron-builder/refs/heads/master/packages/app-builder-lib/scheme.json\",\n  \"compression\": \"maximum\",\n  //\"afterPack\": \"bin/Assets/afterPack.js\",\n  //\"beforePack\": \"bin/Assets/beforePack.js\",\n  \"buildNumber\": \"\",\n  \"linux\": {\n    \"target\": [\n      \"tar.xz\"\n      //\"AppImage\",\n      //\"rpm\",\n      //\"deb\",\n      //\"pacman\"\n    ],\n    \"executableArgs\": [ \"--no-sandbox\" ],\n    \"icon\": \"bin/Assets/icon.png\",\n    \"artifactName\": \"${name}-${arch}-${version}.${ext}\"\n  },\n  \"win\": {\n    \"target\": [\n      {\n        \"target\": \"portable\",\n        \"arch\": \"x64\"\n      }\n    ],\n    \"icon\": \"bin/Assets/icon.ico\"\n  },\n  \"mac\": {\n    \"icon\": \"bin/Assets/icon.icns\"\n  }\n}\n"
  },
  {
    "path": "src/ElectronNET.ConsoleApp/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"DotNet (unpackaged)\": {\n      \"commandName\": \"Project\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"Electron (unpackaged)\": {\n      \"commandName\": \"Executable\",\n      \"executablePath\": \"node\",\n      \"commandLineArgs\": \"node_modules/electron/cli.js main.js -unpackedelectron\",\n      \"workingDirectory\": \"$(TargetDir).electron\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"WSL\": {\n      \"commandName\": \"WSL2\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_URLS\": \"http://localhost:8001/\"\n      },\n      \"distributionName\": \"\"\n    },\n    \"Profile 1\": {\n      \"commandName\": \"Project\"\n    }\n  }\n}"
  },
  {
    "path": "src/ElectronNET.Host/.gitignore",
    "content": "node_modules\nbin"
  },
  {
    "path": "src/ElectronNET.Host/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"name\": \"Launch Electron App\",\n      \"runtimeExecutable\": \"${workspaceFolder}/node_modules/.bin/electron\",\n      \"program\": \"${workspaceFolder}/main.js\",\n      \"skipFiles\": [ \"<node_internals>/**\" ],\n      \"cwd\": \"${workspaceFolder}\",\n      \"console\": \"externalTerminal\",\n      \"args\": [\n        \"--test=true\"\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "src/ElectronNET.Host/.vscode/tasks.json",
    "content": "{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"type\": \"typescript\",\n            \"tsconfig\": \"tsconfig.json\",\n            \"problemMatcher\": [\n                \"$tsc\"\n            ],\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            }\n        }\n    ]\n}"
  },
  {
    "path": "src/ElectronNET.Host/ElectronHostHook/.gitignore",
    "content": "\n# Created by https://www.gitignore.io/api/node\n# Edit at https://www.gitignore.io/?templates=node\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# next.js build output\n.next\n\n# nuxt.js build output\n.nuxt\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# End of https://www.gitignore.io/api/node"
  },
  {
    "path": "src/ElectronNET.Host/ElectronHostHook/connector.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Connector = void 0;\nconst socket_io_1 = require(\"socket.io\");\nclass Connector {\n    socket;\n    app;\n    constructor(socket, \n    // @ts-ignore\n    app) {\n        this.socket = socket;\n        this.app = app;\n    }\n    on(key, javaScriptCode) {\n        this.socket.on(key, (...args) => {\n            const id = args.pop();\n            try {\n                javaScriptCode(...args, (data) => {\n                    if (data) {\n                        this.socket.emit(`${key}Complete${id}`, data);\n                    }\n                });\n            }\n            catch (error) {\n                this.socket.emit(`${key}Error${id}`, `Host Hook Exception`, error);\n            }\n        });\n    }\n}\nexports.Connector = Connector;\n//# sourceMappingURL=connector.js.map"
  },
  {
    "path": "src/ElectronNET.Host/ElectronHostHook/connector.ts",
    "content": "import { Socket } from 'socket.io';\n\nexport class Connector {\n    constructor(private socket: Socket,\n        // @ts-ignore\n        public app: Electron.App) { }\n\n    on(key: string, javaScriptCode: Function): void {\n        this.socket.on(key, (...args: any[]) => {\n            const id: string = args.pop();\n\n            try {\n                javaScriptCode(...args, (data) => {\n                    if (data) {\n                        this.socket.emit(`${key}Complete${id}`, data);\n                    }\n                });\n            } catch (error) {\n                this.socket.emit(`${key}Error${id}`, `Host Hook Exception`, error);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.Host/ElectronHostHook/index.js",
    "content": "\"use strict\";\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n    if (k2 === undefined) k2 = k;\n    var desc = Object.getOwnPropertyDescriptor(m, k);\n    if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n      desc = { enumerable: true, get: function() { return m[k]; } };\n    }\n    Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n    if (k2 === undefined) k2 = k;\n    o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n    Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n    o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || (function () {\n    var ownKeys = function(o) {\n        ownKeys = Object.getOwnPropertyNames || function (o) {\n            var ar = [];\n            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\n            return ar;\n        };\n        return ownKeys(o);\n    };\n    return function (mod) {\n        if (mod && mod.__esModule) return mod;\n        var result = {};\n        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\n        __setModuleDefault(result, mod);\n        return result;\n    };\n})();\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.HookService = void 0;\n// @ts-ignore\nconst Electron = __importStar(require(\"electron\"));\nconst socket_io_1 = require(\"socket.io\");\nconst connector_1 = require(\"./connector\");\nclass HookService extends connector_1.Connector {\n    app;\n    constructor(socket, app) {\n        super(socket, app);\n        this.app = app;\n    }\n    onHostReady() {\n        // execute your own JavaScript Host logic here\n    }\n}\nexports.HookService = HookService;\n//# sourceMappingURL=index.js.map"
  },
  {
    "path": "src/ElectronNET.Host/ElectronHostHook/index.ts",
    "content": "// @ts-ignore\nimport * as Electron from \"electron\";\nimport { Socket } from \"socket.io\";\nimport { Connector } from \"./connector\";\n\nexport class HookService extends Connector {\n    constructor(socket: Socket, public app: Electron.App) {\n        super(socket, app);\n    }\n\n    onHostReady(): void {\n        // execute your own JavaScript Host logic here\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.Host/ElectronHostHook/package.json",
    "content": "{\n  \"name\": \"electron-host-hook\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Connector for Electron.NET projects.\",\n  \"repository\": {\n    \"url\": \"https://github.com/ElectronNET/Electron.NET\"\n  },\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"keywords\": [],\n  \"author\": \"Gregor Biswanger\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n  \"typescript\": \"^5.9.3\"\n  },\n  \"dependencies\": {\n  \"socket.io\": \"^4.8.1\"\n  }\n}\n"
  },
  {
    "path": "src/ElectronNET.Host/ElectronHostHook/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"ES2019\",\n    \"sourceMap\": true,\n    \"skipLibCheck\": true,\n    \"newLine\": \"crlf\"\n  },\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}"
  },
  {
    "path": "src/ElectronNET.Host/ElectronNET.Host.esproj",
    "content": "<Project Sdk=\"Microsoft.VisualStudio.JavaScript.Sdk/1.0.3864779\">\n  <ItemGroup>\n    <None Include=\".vscode\\tasks.json\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/ElectronNET.Host/api/app.js",
    "content": "\"use strict\";\nlet isQuitWindowAllClosed = true;\nlet electronSocket;\nlet appWindowAllClosedEventId;\nmodule.exports = (socket, app) => {\n    electronSocket = socket;\n    // By default, quit when all windows are closed\n    app.on(\"window-all-closed\", () => {\n        // On macOS it is common for applications and their menu bar\n        // to stay active until the user quits explicitly with Cmd + Q\n        if (process.platform !== \"darwin\" && isQuitWindowAllClosed) {\n            app.quit();\n        }\n        else if (appWindowAllClosedEventId) {\n            // If the user is on macOS\n            // - OR -\n            // If the user has indicated NOT to quit when all windows are closed,\n            // emit the event.\n            electronSocket.emit(\"app-window-all-closed\" + appWindowAllClosedEventId);\n        }\n    });\n    socket.on(\"quit-app-window-all-closed\", (quit) => {\n        isQuitWindowAllClosed = quit;\n    });\n    socket.on(\"register-app-window-all-closed\", (id) => {\n        appWindowAllClosedEventId = id;\n    });\n    socket.on(\"register-app-before-quit\", (id) => {\n        app.on(\"before-quit\", (event) => {\n            event.preventDefault();\n            electronSocket.emit(\"app-before-quit\" + id);\n        });\n    });\n    socket.on(\"register-app-will-quit\", (id) => {\n        app.on(\"will-quit\", (event) => {\n            event.preventDefault();\n            electronSocket.emit(\"app-will-quit\" + id);\n        });\n    });\n    socket.on(\"register-app-browser-window-blur\", (id) => {\n        app.on(\"browser-window-blur\", () => {\n            electronSocket.emit(\"app-browser-window-blur\" + id);\n        });\n    });\n    socket.on(\"register-app-browser-window-focus\", (id) => {\n        app.on(\"browser-window-focus\", () => {\n            electronSocket.emit(\"app-browser-window-focus\" + id);\n        });\n    });\n    socket.on(\"register-app-browser-window-created\", (id) => {\n        app.on(\"browser-window-created\", () => {\n            electronSocket.emit(\"app-browser-window-created\" + id);\n        });\n    });\n    socket.on(\"register-app-web-contents-created\", (id) => {\n        app.on(\"web-contents-created\", () => {\n            electronSocket.emit(\"app-web-contents-created\" + id);\n        });\n    });\n    socket.on(\"register-app-accessibility-support-changed\", (id) => {\n        app.on(\"accessibility-support-changed\", (event, accessibilitySupportEnabled) => {\n            electronSocket.emit(\"app-accessibility-support-changed\" + id, accessibilitySupportEnabled);\n        });\n    });\n    socket.on(\"appQuit\", () => {\n        app.quit();\n    });\n    socket.on(\"appExit\", (exitCode = 0) => {\n        app.exit(exitCode);\n    });\n    socket.on(\"appRelaunch\", (options) => {\n        app.relaunch(options);\n    });\n    socket.on(\"appFocus\", (options) => {\n        app.focus(options);\n    });\n    socket.on(\"appHide\", () => {\n        app.hide();\n    });\n    socket.on(\"appShow\", () => {\n        app.show();\n    });\n    socket.on(\"appGetAppPath\", () => {\n        const path = app.getAppPath();\n        electronSocket.emit(\"appGetAppPathCompleted\", path);\n    });\n    socket.on(\"appSetAppLogsPath\", (path) => {\n        app.setAppLogsPath(path);\n    });\n    socket.on(\"appGetPath\", (name) => {\n        const path = app.getPath(name);\n        electronSocket.emit(\"appGetPathCompleted\", path);\n    });\n    socket.on(\"appGetFileIcon\", async (path, options) => {\n        let error = {};\n        if (options) {\n            const nativeImage = await app\n                .getFileIcon(path, options)\n                .catch((errorFileIcon) => (error = errorFileIcon));\n            electronSocket.emit(\"appGetFileIconCompleted\", [error, nativeImage]);\n        }\n        else {\n            const nativeImage = await app\n                .getFileIcon(path)\n                .catch((errorFileIcon) => (error = errorFileIcon));\n            electronSocket.emit(\"appGetFileIconCompleted\", [error, nativeImage]);\n        }\n    });\n    socket.on(\"appSetPath\", (name, path) => {\n        app.setPath(name, path);\n    });\n    socket.on(\"appGetVersion\", () => {\n        const version = app.getVersion();\n        electronSocket.emit(\"appGetVersionCompleted\", version);\n    });\n    socket.on(\"appGetName\", () => {\n        electronSocket.emit(\"appGetNameCompleted\", app.name);\n    });\n    socket.on(\"appSetName\", (name) => {\n        app.name = name;\n    });\n    socket.on(\"appGetLocale\", () => {\n        const locale = app.getLocale();\n        electronSocket.emit(\"appGetLocaleCompleted\", locale);\n    });\n    socket.on(\"appAddRecentDocument\", (path) => {\n        app.addRecentDocument(path);\n    });\n    socket.on(\"appClearRecentDocuments\", () => {\n        app.clearRecentDocuments();\n    });\n    socket.on(\"appSetAsDefaultProtocolClient\", (protocol, path, args) => {\n        const success = app.setAsDefaultProtocolClient(protocol, path, args);\n        electronSocket.emit(\"appSetAsDefaultProtocolClientCompleted\", success);\n    });\n    socket.on(\"appRemoveAsDefaultProtocolClient\", (protocol, path, args) => {\n        const success = app.removeAsDefaultProtocolClient(protocol, path, args);\n        electronSocket.emit(\"appRemoveAsDefaultProtocolClientCompleted\", success);\n    });\n    socket.on(\"appIsDefaultProtocolClient\", (protocol, path, args) => {\n        const success = app.isDefaultProtocolClient(protocol, path, args);\n        electronSocket.emit(\"appIsDefaultProtocolClientCompleted\", success);\n    });\n    socket.on(\"appSetUserTasks\", (tasks) => {\n        const success = app.setUserTasks(tasks);\n        electronSocket.emit(\"appSetUserTasksCompleted\", success);\n    });\n    socket.on(\"appGetJumpListSettings\", () => {\n        const jumpListSettings = app.getJumpListSettings();\n        electronSocket.emit(\"appGetJumpListSettingsCompleted\", jumpListSettings);\n    });\n    socket.on(\"appSetJumpList\", (categories) => {\n        app.setJumpList(categories);\n    });\n    socket.on(\"appRequestSingleInstanceLock\", () => {\n        const success = app.requestSingleInstanceLock();\n        electronSocket.emit(\"appRequestSingleInstanceLockCompleted\", success);\n        app.on(\"second-instance\", (event, args = [], workingDirectory = \"\") => {\n            electronSocket.emit(\"secondInstance\", [args, workingDirectory]);\n        });\n    });\n    socket.on(\"appHasSingleInstanceLock\", () => {\n        const hasLock = app.hasSingleInstanceLock();\n        electronSocket.emit(\"appHasSingleInstanceLockCompleted\", hasLock);\n    });\n    socket.on(\"appReleaseSingleInstanceLock\", () => {\n        app.releaseSingleInstanceLock();\n    });\n    socket.on(\"appSetUserActivity\", (type, userInfo, webpageUrl) => {\n        app.setUserActivity(type, userInfo, webpageUrl);\n    });\n    socket.on(\"appGetCurrentActivityType\", () => {\n        const activityType = app.getCurrentActivityType();\n        electronSocket.emit(\"appGetCurrentActivityTypeCompleted\", activityType);\n    });\n    socket.on(\"appInvalidateCurrentActivity\", () => {\n        app.invalidateCurrentActivity();\n    });\n    socket.on(\"appResignCurrentActivity\", () => {\n        app.resignCurrentActivity();\n    });\n    socket.on(\"appSetAppUserModelId\", (id) => {\n        app.setAppUserModelId(id);\n    });\n    socket.on(\"appImportCertificate\", (options) => {\n        app.importCertificate(options, (result) => {\n            electronSocket.emit(\"appImportCertificateCompleted\", result);\n        });\n    });\n    socket.on(\"appGetAppMetrics\", () => {\n        const processMetrics = app.getAppMetrics();\n        electronSocket.emit(\"appGetAppMetricsCompleted\", processMetrics);\n    });\n    socket.on(\"appGetGpuFeatureStatus\", () => {\n        const gpuFeatureStatus = app.getGPUFeatureStatus();\n        electronSocket.emit(\"appGetGpuFeatureStatusCompleted\", gpuFeatureStatus);\n    });\n    socket.on(\"appSetBadgeCount\", (count) => {\n        const success = app.setBadgeCount(count);\n        electronSocket.emit(\"appSetBadgeCountCompleted\", success);\n    });\n    socket.on(\"appGetBadgeCount\", () => {\n        const count = app.getBadgeCount();\n        electronSocket.emit(\"appGetBadgeCountCompleted\", count);\n    });\n    socket.on(\"appIsUnityRunning\", () => {\n        const isUnityRunning = app.isUnityRunning();\n        electronSocket.emit(\"appIsUnityRunningCompleted\", isUnityRunning);\n    });\n    socket.on(\"appGetLoginItemSettings\", (options) => {\n        const loginItemSettings = app.getLoginItemSettings(options);\n        electronSocket.emit(\"appGetLoginItemSettingsCompleted\", loginItemSettings);\n    });\n    socket.on(\"appSetLoginItemSettings\", (settings) => {\n        app.setLoginItemSettings(settings);\n    });\n    socket.on(\"appIsAccessibilitySupportEnabled\", () => {\n        const isAccessibilitySupportEnabled = app.isAccessibilitySupportEnabled();\n        electronSocket.emit(\"appIsAccessibilitySupportEnabledCompleted\", isAccessibilitySupportEnabled);\n    });\n    socket.on(\"appSetAccessibilitySupportEnabled\", (enabled) => {\n        app.setAccessibilitySupportEnabled(enabled);\n    });\n    socket.on(\"appShowAboutPanel\", () => {\n        app.showAboutPanel();\n    });\n    socket.on(\"appSetAboutPanelOptions\", (options) => {\n        app.setAboutPanelOptions(options);\n    });\n    socket.on(\"appGetUserAgentFallback\", () => {\n        electronSocket.emit(\"appGetUserAgentFallbackCompleted\", app.userAgentFallback);\n    });\n    socket.on(\"appSetUserAgentFallback\", (userAgent) => {\n        app.userAgentFallback = userAgent;\n    });\n    socket.on(\"register-app-on-event\", (eventName, listenerName) => {\n        app.on(eventName, (...args) => {\n            if (args.length > 1) {\n                electronSocket.emit(listenerName, args[1]);\n            }\n            else {\n                electronSocket.emit(listenerName);\n            }\n        });\n    });\n    socket.on(\"register-app-once-event\", (eventName, listenerName) => {\n        app.once(eventName, (...args) => {\n            if (args.length > 1) {\n                electronSocket.emit(listenerName, args[1]);\n            }\n            else {\n                electronSocket.emit(listenerName);\n            }\n        });\n    });\n};\n//# sourceMappingURL=app.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/app.ts",
    "content": "import type { Socket } from \"net\";\nimport {\n  RelaunchOptions,\n  LoginItemSettingsOptions,\n  Settings,\n  AboutPanelOptionsOptions,\n} from \"electron\";\n\nlet isQuitWindowAllClosed = true;\nlet electronSocket: Socket;\nlet appWindowAllClosedEventId: string;\n\nexport = (socket: Socket, app: Electron.App) => {\n  electronSocket = socket;\n\n  // By default, quit when all windows are closed\n  app.on(\"window-all-closed\", () => {\n    // On macOS it is common for applications and their menu bar\n    // to stay active until the user quits explicitly with Cmd + Q\n    if (process.platform !== \"darwin\" && isQuitWindowAllClosed) {\n      app.quit();\n    } else if (appWindowAllClosedEventId) {\n      // If the user is on macOS\n      // - OR -\n      // If the user has indicated NOT to quit when all windows are closed,\n      // emit the event.\n      electronSocket.emit(\"app-window-all-closed\" + appWindowAllClosedEventId);\n    }\n  });\n\n  socket.on(\"quit-app-window-all-closed\", (quit) => {\n    isQuitWindowAllClosed = quit;\n  });\n\n  socket.on(\"register-app-window-all-closed\", (id) => {\n    appWindowAllClosedEventId = id;\n  });\n\n  socket.on(\"register-app-before-quit\", (id) => {\n    app.on(\"before-quit\", (event) => {\n      event.preventDefault();\n\n      electronSocket.emit(\"app-before-quit\" + id);\n    });\n  });\n\n  socket.on(\"register-app-will-quit\", (id) => {\n    app.on(\"will-quit\", (event) => {\n      event.preventDefault();\n\n      electronSocket.emit(\"app-will-quit\" + id);\n    });\n  });\n\n  socket.on(\"register-app-browser-window-blur\", (id) => {\n    app.on(\"browser-window-blur\", () => {\n      electronSocket.emit(\"app-browser-window-blur\" + id);\n    });\n  });\n\n  socket.on(\"register-app-browser-window-focus\", (id) => {\n    app.on(\"browser-window-focus\", () => {\n      electronSocket.emit(\"app-browser-window-focus\" + id);\n    });\n  });\n\n  socket.on(\"register-app-browser-window-created\", (id) => {\n    app.on(\"browser-window-created\", () => {\n      electronSocket.emit(\"app-browser-window-created\" + id);\n    });\n  });\n\n  socket.on(\"register-app-web-contents-created\", (id) => {\n    app.on(\"web-contents-created\", () => {\n      electronSocket.emit(\"app-web-contents-created\" + id);\n    });\n  });\n\n  socket.on(\"register-app-accessibility-support-changed\", (id) => {\n    app.on(\n      \"accessibility-support-changed\",\n      (event, accessibilitySupportEnabled) => {\n        electronSocket.emit(\n          \"app-accessibility-support-changed\" + id,\n          accessibilitySupportEnabled,\n        );\n      },\n    );\n  });\n\n  socket.on(\"appQuit\", () => {\n    app.quit();\n  });\n\n  socket.on(\"appExit\", (exitCode = 0) => {\n    app.exit(exitCode);\n  });\n\n  socket.on(\"appRelaunch\", (options) => {\n    app.relaunch(options as RelaunchOptions);\n  });\n\n  socket.on(\"appFocus\", (options) => {\n    app.focus(options);\n  });\n\n  socket.on(\"appHide\", () => {\n    app.hide();\n  });\n\n  socket.on(\"appShow\", () => {\n    app.show();\n  });\n\n  socket.on(\"appGetAppPath\", () => {\n    const path = app.getAppPath();\n    electronSocket.emit(\"appGetAppPathCompleted\", path);\n  });\n\n  socket.on(\"appSetAppLogsPath\", (path) => {\n    app.setAppLogsPath(path);\n  });\n\n  socket.on(\"appGetPath\", (name) => {\n    const path = app.getPath(name);\n    electronSocket.emit(\"appGetPathCompleted\", path);\n  });\n\n  socket.on(\"appGetFileIcon\", async (path, options) => {\n    let error = {};\n\n    if (options) {\n      const nativeImage = await app\n        .getFileIcon(path, options)\n        .catch((errorFileIcon) => (error = errorFileIcon));\n\n      electronSocket.emit(\"appGetFileIconCompleted\", [error, nativeImage]);\n    } else {\n      const nativeImage = await app\n        .getFileIcon(path)\n        .catch((errorFileIcon) => (error = errorFileIcon));\n\n      electronSocket.emit(\"appGetFileIconCompleted\", [error, nativeImage]);\n    }\n  });\n\n  socket.on(\"appSetPath\", (name, path) => {\n    app.setPath(name, path);\n  });\n\n  socket.on(\"appGetVersion\", () => {\n    const version = app.getVersion();\n    electronSocket.emit(\"appGetVersionCompleted\", version);\n  });\n\n  socket.on(\"appGetName\", () => {\n    electronSocket.emit(\"appGetNameCompleted\", app.name);\n  });\n\n  socket.on(\"appSetName\", (name) => {\n    app.name = name;\n  });\n\n  socket.on(\"appGetLocale\", () => {\n    const locale = app.getLocale();\n    electronSocket.emit(\"appGetLocaleCompleted\", locale);\n  });\n\n  socket.on(\"appAddRecentDocument\", (path) => {\n    app.addRecentDocument(path);\n  });\n\n  socket.on(\"appClearRecentDocuments\", () => {\n    app.clearRecentDocuments();\n  });\n\n  socket.on(\"appSetAsDefaultProtocolClient\", (protocol, path, args) => {\n    const success = app.setAsDefaultProtocolClient(protocol, path, args);\n    electronSocket.emit(\"appSetAsDefaultProtocolClientCompleted\", success);\n  });\n\n  socket.on(\"appRemoveAsDefaultProtocolClient\", (protocol, path, args) => {\n    const success = app.removeAsDefaultProtocolClient(protocol, path, args);\n    electronSocket.emit(\"appRemoveAsDefaultProtocolClientCompleted\", success);\n  });\n\n  socket.on(\"appIsDefaultProtocolClient\", (protocol, path, args) => {\n    const success = app.isDefaultProtocolClient(protocol, path, args);\n    electronSocket.emit(\"appIsDefaultProtocolClientCompleted\", success);\n  });\n\n  socket.on(\"appSetUserTasks\", (tasks) => {\n    const success = app.setUserTasks(tasks);\n    electronSocket.emit(\"appSetUserTasksCompleted\", success);\n  });\n\n  socket.on(\"appGetJumpListSettings\", () => {\n    const jumpListSettings = app.getJumpListSettings();\n    electronSocket.emit(\"appGetJumpListSettingsCompleted\", jumpListSettings);\n  });\n\n  socket.on(\"appSetJumpList\", (categories) => {\n    app.setJumpList(categories);\n  });\n\n  socket.on(\"appRequestSingleInstanceLock\", () => {\n    const success = app.requestSingleInstanceLock();\n    electronSocket.emit(\"appRequestSingleInstanceLockCompleted\", success);\n\n    app.on(\"second-instance\", (event, args = [], workingDirectory = \"\") => {\n      electronSocket.emit(\"secondInstance\", [args, workingDirectory]);\n    });\n  });\n\n  socket.on(\"appHasSingleInstanceLock\", () => {\n    const hasLock = app.hasSingleInstanceLock();\n\n    electronSocket.emit(\"appHasSingleInstanceLockCompleted\", hasLock);\n  });\n\n  socket.on(\"appReleaseSingleInstanceLock\", () => {\n    app.releaseSingleInstanceLock();\n  });\n\n  socket.on(\"appSetUserActivity\", (type, userInfo, webpageUrl) => {\n    app.setUserActivity(type, userInfo, webpageUrl);\n  });\n\n  socket.on(\"appGetCurrentActivityType\", () => {\n    const activityType = app.getCurrentActivityType();\n    electronSocket.emit(\"appGetCurrentActivityTypeCompleted\", activityType);\n  });\n\n  socket.on(\"appInvalidateCurrentActivity\", () => {\n    app.invalidateCurrentActivity();\n  });\n\n  socket.on(\"appResignCurrentActivity\", () => {\n    app.resignCurrentActivity();\n  });\n\n  socket.on(\"appSetAppUserModelId\", (id) => {\n    app.setAppUserModelId(id);\n  });\n\n  socket.on(\"appImportCertificate\", (options) => {\n    app.importCertificate(options, (result) => {\n      electronSocket.emit(\"appImportCertificateCompleted\", result);\n    });\n  });\n\n  socket.on(\"appGetAppMetrics\", () => {\n    const processMetrics = app.getAppMetrics();\n    electronSocket.emit(\"appGetAppMetricsCompleted\", processMetrics);\n  });\n\n  socket.on(\"appGetGpuFeatureStatus\", () => {\n    const gpuFeatureStatus = app.getGPUFeatureStatus();\n    electronSocket.emit(\"appGetGpuFeatureStatusCompleted\", gpuFeatureStatus);\n  });\n\n  socket.on(\"appSetBadgeCount\", (count) => {\n    const success = app.setBadgeCount(count);\n    electronSocket.emit(\"appSetBadgeCountCompleted\", success);\n  });\n\n  socket.on(\"appGetBadgeCount\", () => {\n    const count = app.getBadgeCount();\n    electronSocket.emit(\"appGetBadgeCountCompleted\", count);\n  });\n\n  socket.on(\"appIsUnityRunning\", () => {\n    const isUnityRunning = app.isUnityRunning();\n    electronSocket.emit(\"appIsUnityRunningCompleted\", isUnityRunning);\n  });\n\n  socket.on(\"appGetLoginItemSettings\", (options) => {\n    const loginItemSettings = app.getLoginItemSettings(\n      options as LoginItemSettingsOptions,\n    );\n    electronSocket.emit(\"appGetLoginItemSettingsCompleted\", loginItemSettings);\n  });\n\n  socket.on(\"appSetLoginItemSettings\", (settings) => {\n    app.setLoginItemSettings(settings as Settings);\n  });\n\n  socket.on(\"appIsAccessibilitySupportEnabled\", () => {\n    const isAccessibilitySupportEnabled = app.isAccessibilitySupportEnabled();\n    electronSocket.emit(\n      \"appIsAccessibilitySupportEnabledCompleted\",\n      isAccessibilitySupportEnabled,\n    );\n  });\n\n  socket.on(\"appSetAccessibilitySupportEnabled\", (enabled) => {\n    app.setAccessibilitySupportEnabled(enabled);\n  });\n\n  socket.on(\"appShowAboutPanel\", () => {\n    app.showAboutPanel();\n  });\n\n  socket.on(\"appSetAboutPanelOptions\", (options) => {\n    app.setAboutPanelOptions(options as AboutPanelOptionsOptions);\n  });\n\n  socket.on(\"appGetUserAgentFallback\", () => {\n    electronSocket.emit(\n      \"appGetUserAgentFallbackCompleted\",\n      app.userAgentFallback,\n    );\n  });\n\n  socket.on(\"appSetUserAgentFallback\", (userAgent) => {\n    app.userAgentFallback = userAgent;\n  });\n\n  socket.on(\"register-app-on-event\", (eventName, listenerName) => {\n    app.on(eventName, (...args) => {\n      if (args.length > 1) {\n        electronSocket.emit(listenerName, args[1]);\n      } else {\n        electronSocket.emit(listenerName);\n      }\n    });\n  });\n\n  socket.on(\"register-app-once-event\", (eventName, listenerName) => {\n    app.once(eventName, (...args) => {\n      if (args.length > 1) {\n        electronSocket.emit(listenerName, args[1]);\n      } else {\n        electronSocket.emit(listenerName);\n      }\n    });\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/autoUpdater.js",
    "content": "\"use strict\";\nconst electron_updater_1 = require(\"electron-updater\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"register-autoUpdater-error\", (id) => {\n        electron_updater_1.autoUpdater.on(\"error\", (error) => {\n            electronSocket.emit(\"autoUpdater-error\" + id, error.message);\n        });\n    });\n    socket.on(\"register-autoUpdater-checking-for-update\", (id) => {\n        electron_updater_1.autoUpdater.on(\"checking-for-update\", () => {\n            electronSocket.emit(\"autoUpdater-checking-for-update\" + id);\n        });\n    });\n    socket.on(\"register-autoUpdater-update-available\", (id) => {\n        electron_updater_1.autoUpdater.on(\"update-available\", (updateInfo) => {\n            electronSocket.emit(\"autoUpdater-update-available\" + id, updateInfo);\n        });\n    });\n    socket.on(\"register-autoUpdater-update-not-available\", (id) => {\n        electron_updater_1.autoUpdater.on(\"update-not-available\", (updateInfo) => {\n            electronSocket.emit(\"autoUpdater-update-not-available\" + id, updateInfo);\n        });\n    });\n    socket.on(\"register-autoUpdater-download-progress\", (id) => {\n        electron_updater_1.autoUpdater.on(\"download-progress\", (progressInfo) => {\n            electronSocket.emit(\"autoUpdater-download-progress\" + id, progressInfo);\n        });\n    });\n    socket.on(\"register-autoUpdater-update-downloaded\", (id) => {\n        electron_updater_1.autoUpdater.on(\"update-downloaded\", (updateInfo) => {\n            electronSocket.emit(\"autoUpdater-update-downloaded\" + id, updateInfo);\n        });\n    });\n    // Properties *****\n    socket.on(\"autoUpdater-autoDownload\", () => {\n        electronSocket.emit(\"autoUpdater-autoDownload-completed\", electron_updater_1.autoUpdater.autoDownload);\n    });\n    socket.on(\"autoUpdater-autoDownload-set\", (value) => {\n        electron_updater_1.autoUpdater.autoDownload = value;\n    });\n    socket.on(\"autoUpdater-autoInstallOnAppQuit\", () => {\n        electronSocket.emit(\"autoUpdater-autoInstallOnAppQuit-completed\", electron_updater_1.autoUpdater.autoInstallOnAppQuit);\n    });\n    socket.on(\"autoUpdater-autoInstallOnAppQuit-set\", (value) => {\n        electron_updater_1.autoUpdater.autoInstallOnAppQuit = value;\n    });\n    socket.on(\"autoUpdater-allowPrerelease\", () => {\n        electronSocket.emit(\"autoUpdater-allowPrerelease-completed\", electron_updater_1.autoUpdater.allowPrerelease);\n    });\n    socket.on(\"autoUpdater-allowPrerelease-set\", (value) => {\n        electron_updater_1.autoUpdater.allowPrerelease = value;\n    });\n    socket.on(\"autoUpdater-fullChangelog\", () => {\n        electronSocket.emit(\"autoUpdater-fullChangelog-completed\", electron_updater_1.autoUpdater.fullChangelog);\n    });\n    socket.on(\"autoUpdater-fullChangelog-set\", (value) => {\n        electron_updater_1.autoUpdater.fullChangelog = value;\n    });\n    socket.on(\"autoUpdater-allowDowngrade\", () => {\n        electronSocket.emit(\"autoUpdater-allowDowngrade-completed\", electron_updater_1.autoUpdater.allowDowngrade);\n    });\n    socket.on(\"autoUpdater-allowDowngrade-set\", (value) => {\n        electron_updater_1.autoUpdater.allowDowngrade = value;\n    });\n    socket.on(\"autoUpdater-updateConfigPath\", () => {\n        electronSocket.emit(\"autoUpdater-updateConfigPath-completed\", electron_updater_1.autoUpdater.updateConfigPath || \"\");\n    });\n    socket.on(\"autoUpdater-updateConfigPath-set\", (value) => {\n        electron_updater_1.autoUpdater.updateConfigPath = value;\n    });\n    socket.on(\"autoUpdater-currentVersion\", () => {\n        electronSocket.emit(\"autoUpdater-currentVersion-completed\", electron_updater_1.autoUpdater.currentVersion);\n    });\n    socket.on(\"autoUpdater-channel\", () => {\n        electronSocket.emit(\"autoUpdater-channel-completed\", electron_updater_1.autoUpdater.channel || \"\");\n    });\n    socket.on(\"autoUpdater-channel-set\", (value) => {\n        electron_updater_1.autoUpdater.channel = value;\n    });\n    socket.on(\"autoUpdater-requestHeaders\", () => {\n        electronSocket.emit(\"autoUpdater-requestHeaders-completed\", electron_updater_1.autoUpdater.requestHeaders);\n    });\n    socket.on(\"autoUpdater-requestHeaders-set\", (value) => {\n        electron_updater_1.autoUpdater.requestHeaders = value;\n    });\n    socket.on(\"autoUpdater-checkForUpdatesAndNotify\", async (guid) => {\n        electron_updater_1.autoUpdater\n            .checkForUpdatesAndNotify()\n            .then((updateCheckResult) => {\n            electronSocket.emit(\"autoUpdater-checkForUpdatesAndNotify-completed\" + guid, updateCheckResult);\n        })\n            .catch((error) => {\n            electronSocket.emit(\"autoUpdater-checkForUpdatesAndNotifyError\" + guid, error);\n        });\n    });\n    socket.on(\"autoUpdater-checkForUpdates\", async (guid) => {\n        electron_updater_1.autoUpdater\n            .checkForUpdates()\n            .then((updateCheckResult) => {\n            electronSocket.emit(\"autoUpdater-checkForUpdates-completed\" + guid, updateCheckResult);\n        })\n            .catch((error) => {\n            electronSocket.emit(\"autoUpdater-checkForUpdatesError\" + guid, error);\n        });\n    });\n    socket.on(\"autoUpdater-quitAndInstall\", async (isSilent, isForceRunAfter) => {\n        electron_updater_1.autoUpdater.quitAndInstall(isSilent, isForceRunAfter);\n    });\n    socket.on(\"autoUpdater-downloadUpdate\", async (guid) => {\n        const downloadedPath = await electron_updater_1.autoUpdater.downloadUpdate();\n        electronSocket.emit(\"autoUpdater-downloadUpdate-completed\" + guid, downloadedPath);\n    });\n    socket.on(\"autoUpdater-getFeedURL\", async (guid) => {\n        const feedUrl = await electron_updater_1.autoUpdater.getFeedURL();\n        electronSocket.emit(\"autoUpdater-getFeedURL-completed\" + guid, feedUrl || \"\");\n    });\n};\n//# sourceMappingURL=autoUpdater.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/autoUpdater.ts",
    "content": "import type { Socket } from \"net\";\nimport { autoUpdater } from \"electron-updater\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n\n  socket.on(\"register-autoUpdater-error\", (id) => {\n    autoUpdater.on(\"error\", (error) => {\n      electronSocket.emit(\"autoUpdater-error\" + id, error.message);\n    });\n  });\n\n  socket.on(\"register-autoUpdater-checking-for-update\", (id) => {\n    autoUpdater.on(\"checking-for-update\", () => {\n      electronSocket.emit(\"autoUpdater-checking-for-update\" + id);\n    });\n  });\n\n  socket.on(\"register-autoUpdater-update-available\", (id) => {\n    autoUpdater.on(\"update-available\", (updateInfo) => {\n      electronSocket.emit(\"autoUpdater-update-available\" + id, updateInfo);\n    });\n  });\n\n  socket.on(\"register-autoUpdater-update-not-available\", (id) => {\n    autoUpdater.on(\"update-not-available\", (updateInfo) => {\n      electronSocket.emit(\"autoUpdater-update-not-available\" + id, updateInfo);\n    });\n  });\n\n  socket.on(\"register-autoUpdater-download-progress\", (id) => {\n    autoUpdater.on(\"download-progress\", (progressInfo) => {\n      electronSocket.emit(\"autoUpdater-download-progress\" + id, progressInfo);\n    });\n  });\n\n  socket.on(\"register-autoUpdater-update-downloaded\", (id) => {\n    autoUpdater.on(\"update-downloaded\", (updateInfo) => {\n      electronSocket.emit(\"autoUpdater-update-downloaded\" + id, updateInfo);\n    });\n  });\n\n  // Properties *****\n\n  socket.on(\"autoUpdater-autoDownload\", () => {\n    electronSocket.emit(\n      \"autoUpdater-autoDownload-completed\",\n      autoUpdater.autoDownload,\n    );\n  });\n\n  socket.on(\"autoUpdater-autoDownload-set\", (value) => {\n    autoUpdater.autoDownload = value;\n  });\n\n  socket.on(\"autoUpdater-autoInstallOnAppQuit\", () => {\n    electronSocket.emit(\n      \"autoUpdater-autoInstallOnAppQuit-completed\",\n      autoUpdater.autoInstallOnAppQuit,\n    );\n  });\n\n  socket.on(\"autoUpdater-autoInstallOnAppQuit-set\", (value) => {\n    autoUpdater.autoInstallOnAppQuit = value;\n  });\n\n  socket.on(\"autoUpdater-allowPrerelease\", () => {\n    electronSocket.emit(\n      \"autoUpdater-allowPrerelease-completed\",\n      autoUpdater.allowPrerelease,\n    );\n  });\n\n  socket.on(\"autoUpdater-allowPrerelease-set\", (value) => {\n    autoUpdater.allowPrerelease = value;\n  });\n\n  socket.on(\"autoUpdater-fullChangelog\", () => {\n    electronSocket.emit(\n      \"autoUpdater-fullChangelog-completed\",\n      autoUpdater.fullChangelog,\n    );\n  });\n\n  socket.on(\"autoUpdater-fullChangelog-set\", (value) => {\n    autoUpdater.fullChangelog = value;\n  });\n\n  socket.on(\"autoUpdater-allowDowngrade\", () => {\n    electronSocket.emit(\n      \"autoUpdater-allowDowngrade-completed\",\n      autoUpdater.allowDowngrade,\n    );\n  });\n\n  socket.on(\"autoUpdater-allowDowngrade-set\", (value) => {\n    autoUpdater.allowDowngrade = value;\n  });\n\n  socket.on(\"autoUpdater-updateConfigPath\", () => {\n    electronSocket.emit(\n      \"autoUpdater-updateConfigPath-completed\",\n      autoUpdater.updateConfigPath || \"\",\n    );\n  });\n\n  socket.on(\"autoUpdater-updateConfigPath-set\", (value) => {\n    autoUpdater.updateConfigPath = value;\n  });\n\n  socket.on(\"autoUpdater-currentVersion\", () => {\n    electronSocket.emit(\n      \"autoUpdater-currentVersion-completed\",\n      autoUpdater.currentVersion,\n    );\n  });\n\n  socket.on(\"autoUpdater-channel\", () => {\n    electronSocket.emit(\n      \"autoUpdater-channel-completed\",\n      autoUpdater.channel || \"\",\n    );\n  });\n\n  socket.on(\"autoUpdater-channel-set\", (value) => {\n    autoUpdater.channel = value;\n  });\n\n  socket.on(\"autoUpdater-requestHeaders\", () => {\n    electronSocket.emit(\n      \"autoUpdater-requestHeaders-completed\",\n      autoUpdater.requestHeaders,\n    );\n  });\n\n  socket.on(\"autoUpdater-requestHeaders-set\", (value) => {\n    autoUpdater.requestHeaders = value;\n  });\n\n  socket.on(\"autoUpdater-checkForUpdatesAndNotify\", async (guid) => {\n    autoUpdater\n      .checkForUpdatesAndNotify()\n      .then((updateCheckResult) => {\n        electronSocket.emit(\n          \"autoUpdater-checkForUpdatesAndNotify-completed\" + guid,\n          updateCheckResult,\n        );\n      })\n      .catch((error) => {\n        electronSocket.emit(\n          \"autoUpdater-checkForUpdatesAndNotifyError\" + guid,\n          error,\n        );\n      });\n  });\n\n  socket.on(\"autoUpdater-checkForUpdates\", async (guid) => {\n    autoUpdater\n      .checkForUpdates()\n      .then((updateCheckResult) => {\n        electronSocket.emit(\n          \"autoUpdater-checkForUpdates-completed\" + guid,\n          updateCheckResult,\n        );\n      })\n      .catch((error) => {\n        electronSocket.emit(\"autoUpdater-checkForUpdatesError\" + guid, error);\n      });\n  });\n\n  socket.on(\"autoUpdater-quitAndInstall\", async (isSilent, isForceRunAfter) => {\n    autoUpdater.quitAndInstall(isSilent, isForceRunAfter);\n  });\n\n  socket.on(\"autoUpdater-downloadUpdate\", async (guid) => {\n    const downloadedPath = await autoUpdater.downloadUpdate();\n    electronSocket.emit(\n      \"autoUpdater-downloadUpdate-completed\" + guid,\n      downloadedPath,\n    );\n  });\n\n  socket.on(\"autoUpdater-getFeedURL\", async (guid) => {\n    const feedUrl = await autoUpdater.getFeedURL();\n    electronSocket.emit(\n      \"autoUpdater-getFeedURL-completed\" + guid,\n      feedUrl || \"\",\n    );\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/browserView.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.browserViewMediateService = exports.browserViewApi = void 0;\nconst electron_1 = require(\"electron\");\nconst browserViews = (global[\"browserViews\"] =\n    global[\"browserViews\"] || []);\nconst proxyToCredentialsMap = (global[\"proxyToCredentialsMap\"] = global[\"proxyToCredentialsMap\"] || []);\nlet browserView;\nlet electronSocket;\nconst browserViewApi = (socket) => {\n    electronSocket = socket;\n    socket.on(\"createBrowserView\", (options) => {\n        if (!hasOwnChildreen(options, \"webPreferences\", \"nodeIntegration\")) {\n            options = {\n                ...options,\n                webPreferences: { nodeIntegration: true, contextIsolation: false },\n            };\n        }\n        browserView = new electron_1.BrowserView(options);\n        browserView[\"id\"] = browserViews.length + 1;\n        if (options.proxy) {\n            browserView.webContents.session.setProxy({ proxyRules: options.proxy });\n        }\n        if (options.proxy && options.proxyCredentials) {\n            proxyToCredentialsMap[options.proxy] = options.proxyCredentials;\n        }\n        browserViews.push(browserView);\n        electronSocket.emit(\"BrowserViewCreated\", browserView[\"id\"]);\n    });\n    socket.on(\"browserView-bounds\", (id) => {\n        const bounds = getBrowserViewById(id).getBounds();\n        electronSocket.emit(\"browserView-bounds-completed\", bounds);\n    });\n    socket.on(\"browserView-bounds-set\", (id, bounds) => {\n        getBrowserViewById(id).setBounds(bounds);\n    });\n    socket.on(\"browserView-setAutoResize\", (id, options) => {\n        getBrowserViewById(id).setAutoResize(options);\n    });\n    socket.on(\"browserView-setBackgroundColor\", (id, color) => {\n        getBrowserViewById(id).setBackgroundColor(color);\n    });\n    function hasOwnChildreen(obj, ...childNames) {\n        for (let i = 0; i < childNames.length; i++) {\n            if (!obj || !obj.hasOwnProperty(childNames[i])) {\n                return false;\n            }\n            obj = obj[childNames[i]];\n        }\n        return true;\n    }\n};\nexports.browserViewApi = browserViewApi;\nconst browserViewMediateService = (browserViewId) => {\n    return getBrowserViewById(browserViewId);\n};\nexports.browserViewMediateService = browserViewMediateService;\nfunction getBrowserViewById(id) {\n    for (let index = 0; index < browserViews.length; index++) {\n        const browserViewItem = browserViews[index];\n        if (browserViewItem[\"id\"] === id) {\n            return browserViewItem;\n        }\n    }\n}\n//# sourceMappingURL=browserView.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/browserView.ts",
    "content": "import type { Socket } from \"net\";\nimport { BrowserView } from \"electron\";\n\nconst browserViews: BrowserView[] = (global[\"browserViews\"] =\n  global[\"browserViews\"] || []) as BrowserView[];\nconst proxyToCredentialsMap: { [proxy: string]: string } = (global[\n  \"proxyToCredentialsMap\"\n] = global[\"proxyToCredentialsMap\"] || []) as { [proxy: string]: string };\n\nlet browserView: BrowserView;\nlet electronSocket: Socket;\n\nconst browserViewApi = (socket: Socket) => {\n  electronSocket = socket;\n\n  socket.on(\"createBrowserView\", (options) => {\n    if (!hasOwnChildreen(options, \"webPreferences\", \"nodeIntegration\")) {\n      options = {\n        ...options,\n        webPreferences: { nodeIntegration: true, contextIsolation: false },\n      };\n    }\n\n    browserView = new BrowserView(options);\n    browserView[\"id\"] = browserViews.length + 1;\n\n    if (options.proxy) {\n      browserView.webContents.session.setProxy({ proxyRules: options.proxy });\n    }\n\n    if (options.proxy && options.proxyCredentials) {\n      proxyToCredentialsMap[options.proxy] = options.proxyCredentials;\n    }\n\n    browserViews.push(browserView);\n\n    electronSocket.emit(\"BrowserViewCreated\", browserView[\"id\"]);\n  });\n\n  socket.on(\"browserView-bounds\", (id) => {\n    const bounds = getBrowserViewById(id).getBounds();\n\n    electronSocket.emit(\"browserView-bounds-completed\", bounds);\n  });\n\n  socket.on(\"browserView-bounds-set\", (id, bounds) => {\n    getBrowserViewById(id).setBounds(bounds);\n  });\n\n  socket.on(\"browserView-setAutoResize\", (id, options) => {\n    getBrowserViewById(id).setAutoResize(options);\n  });\n\n  socket.on(\"browserView-setBackgroundColor\", (id, color) => {\n    getBrowserViewById(id).setBackgroundColor(color);\n  });\n\n  function hasOwnChildreen(obj, ...childNames) {\n    for (let i = 0; i < childNames.length; i++) {\n      if (!obj || !obj.hasOwnProperty(childNames[i])) {\n        return false;\n      }\n      obj = obj[childNames[i]];\n    }\n\n    return true;\n  }\n};\n\nconst browserViewMediateService = (browserViewId: number): BrowserView => {\n  return getBrowserViewById(browserViewId);\n};\n\nfunction getBrowserViewById(id: number) {\n  for (let index = 0; index < browserViews.length; index++) {\n    const browserViewItem = browserViews[index];\n    if (browserViewItem[\"id\"] === id) {\n      return browserViewItem;\n    }\n  }\n}\n\nexport { browserViewApi, browserViewMediateService };\n"
  },
  {
    "path": "src/ElectronNET.Host/api/browserWindows.js",
    "content": "\"use strict\";\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n    if (k2 === undefined) k2 = k;\n    var desc = Object.getOwnPropertyDescriptor(m, k);\n    if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n      desc = { enumerable: true, get: function() { return m[k]; } };\n    }\n    Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n    if (k2 === undefined) k2 = k;\n    o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n    Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n    o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || (function () {\n    var ownKeys = function(o) {\n        ownKeys = Object.getOwnPropertyNames || function (o) {\n            var ar = [];\n            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\n            return ar;\n        };\n        return ownKeys(o);\n    };\n    return function (mod) {\n        if (mod && mod.__esModule) return mod;\n        var result = {};\n        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\n        __setModuleDefault(result, mod);\n        return result;\n    };\n})();\nconst path = __importStar(require(\"path\"));\nconst electron_1 = require(\"electron\");\nconst browserView_1 = require(\"./browserView\");\nconst windows = (global[\"browserWindows\"] =\n    global[\"browserWindows\"] || []);\nlet readyToShowWindowsIds = [];\nlet window;\nlet lastOptions;\nlet electronSocket;\nconst proxyToCredentialsMap = (global[\"proxyToCredentialsMap\"] = global[\"proxyToCredentialsMap\"] || []);\nmodule.exports = (socket, app) => {\n    electronSocket = socket;\n    app.on(\"login\", (event, webContents, request, authInfo, callback) => {\n        if (authInfo.isProxy) {\n            let proxy = `${authInfo.host}:${authInfo.port}`;\n            if (proxy in proxyToCredentialsMap &&\n                proxyToCredentialsMap[proxy].split(\":\").length === 2) {\n                event.preventDefault();\n                let user = proxyToCredentialsMap[proxy].split(\":\")[0];\n                let pass = proxyToCredentialsMap[proxy].split(\":\")[1];\n                callback(user, pass);\n            }\n        }\n    });\n    socket.on(\"register-browserWindow-ready-to-show\", (id) => {\n        if (readyToShowWindowsIds.includes(id)) {\n            readyToShowWindowsIds = readyToShowWindowsIds.filter((value) => value !== id);\n            electronSocket.emit(\"browserWindow-ready-to-show\" + id);\n        }\n        getWindowById(id).on(\"ready-to-show\", () => {\n            readyToShowWindowsIds.push(id);\n            electronSocket.emit(\"browserWindow-ready-to-show\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-page-title-updated\", (id) => {\n        getWindowById(id).on(\"page-title-updated\", (event, title) => {\n            electronSocket.emit(\"browserWindow-page-title-updated\" + id, title);\n        });\n    });\n    socket.on(\"register-browserWindow-close\", (id) => {\n        getWindowById(id).on(\"close\", () => {\n            electronSocket.emit(\"browserWindow-close\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-closed\", (id) => {\n        getWindowById(id).on(\"closed\", () => {\n            electronSocket.emit(\"browserWindow-closed\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-session-end\", (id) => {\n        getWindowById(id).on(\"session-end\", () => {\n            electronSocket.emit(\"browserWindow-session-end\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-unresponsive\", (id) => {\n        getWindowById(id).on(\"unresponsive\", () => {\n            electronSocket.emit(\"browserWindow-unresponsive\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-responsive\", (id) => {\n        getWindowById(id).on(\"responsive\", () => {\n            electronSocket.emit(\"browserWindow-responsive\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-blur\", (id) => {\n        getWindowById(id).on(\"blur\", () => {\n            electronSocket.emit(\"browserWindow-blur\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-focus\", (id) => {\n        getWindowById(id).on(\"focus\", () => {\n            electronSocket.emit(\"browserWindow-focus\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-show\", (id) => {\n        getWindowById(id).on(\"show\", () => {\n            electronSocket.emit(\"browserWindow-show\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-hide\", (id) => {\n        getWindowById(id).on(\"hide\", () => {\n            electronSocket.emit(\"browserWindow-hide\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-maximize\", (id) => {\n        getWindowById(id).on(\"maximize\", () => {\n            electronSocket.emit(\"browserWindow-maximize\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-unmaximize\", (id) => {\n        getWindowById(id).on(\"unmaximize\", () => {\n            electronSocket.emit(\"browserWindow-unmaximize\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-minimize\", (id) => {\n        getWindowById(id).on(\"minimize\", () => {\n            electronSocket.emit(\"browserWindow-minimize\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-restore\", (id) => {\n        getWindowById(id).on(\"restore\", () => {\n            electronSocket.emit(\"browserWindow-restore\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-resize\", (id) => {\n        getWindowById(id).on(\"resize\", () => {\n            electronSocket.emit(\"browserWindow-resize\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-move\", (id) => {\n        getWindowById(id).on(\"move\", () => {\n            electronSocket.emit(\"browserWindow-move\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-bounds-changed\", (id) => {\n        const window = getWindowById(id);\n        const cb = () => electronSocket.emit(\"browserWindow-bounds-changed\" + id, window.getBounds());\n        window.on(\"resize\", cb);\n        window.on(\"move\", cb);\n    });\n    socket.on(\"register-browserWindow-moved\", (id) => {\n        getWindowById(id).on(\"moved\", () => {\n            electronSocket.emit(\"browserWindow-moved\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-enter-full-screen\", (id) => {\n        getWindowById(id).on(\"enter-full-screen\", () => {\n            electronSocket.emit(\"browserWindow-enter-full-screen\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-leave-full-screen\", (id) => {\n        getWindowById(id).on(\"leave-full-screen\", () => {\n            electronSocket.emit(\"browserWindow-leave-full-screen\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-enter-html-full-screen\", (id) => {\n        getWindowById(id).on(\"enter-html-full-screen\", () => {\n            electronSocket.emit(\"browserWindow-enter-html-full-screen\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-leave-html-full-screen\", (id) => {\n        getWindowById(id).on(\"leave-html-full-screen\", () => {\n            electronSocket.emit(\"browserWindow-leave-html-full-screen\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-app-command\", (id) => {\n        getWindowById(id).on(\"app-command\", (event, command) => {\n            electronSocket.emit(\"browserWindow-app-command\" + id, command);\n        });\n    });\n    socket.on(\"register-browserWindow-swipe\", (id) => {\n        getWindowById(id).on(\"swipe\", (event, direction) => {\n            electronSocket.emit(\"browserWindow-swipe\" + id, direction);\n        });\n    });\n    socket.on(\"register-browserWindow-sheet-begin\", (id) => {\n        getWindowById(id).on(\"sheet-begin\", () => {\n            electronSocket.emit(\"browserWindow-sheet-begin\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-sheet-end\", (id) => {\n        getWindowById(id).on(\"sheet-end\", () => {\n            electronSocket.emit(\"browserWindow-sheet-end\" + id);\n        });\n    });\n    socket.on(\"register-browserWindow-new-window-for-tab\", (id) => {\n        getWindowById(id).on(\"new-window-for-tab\", () => {\n            electronSocket.emit(\"browserWindow-new-window-for-tab\" + id);\n        });\n    });\n    socket.on(\"createBrowserWindow\", (options, loadUrl) => {\n        if (options.webPreferences &&\n            !(\"nodeIntegration\" in options.webPreferences)) {\n            options = {\n                ...options,\n                webPreferences: {\n                    ...options.webPreferences,\n                    nodeIntegration: true,\n                    contextIsolation: false,\n                },\n            };\n        }\n        else if (!options.webPreferences) {\n            options = {\n                ...options,\n                webPreferences: { nodeIntegration: true, contextIsolation: false },\n            };\n        }\n        if (options.isRunningBlazor) {\n            options.webPreferences[\"preload\"] = path.join(__dirname, \"..\", \"scripts\", \"blazor-preload.js\");\n        }\n        delete options.isRunningBlazor;\n        // we dont want to recreate the window when watch is ready.\n        if (app.commandLine.hasSwitch(\"watch\") &&\n            app[\"mainWindowURL\"] === loadUrl) {\n            window = app[\"mainWindow\"];\n            if (window) {\n                window.reload();\n                windows.push(window);\n                electronSocket.emit(\"BrowserWindowCreated\", window.id);\n                return;\n            }\n        }\n        else {\n            window = new electron_1.BrowserWindow(options);\n        }\n        if (options.proxy) {\n            window.webContents.session.setProxy({ proxyRules: options.proxy });\n        }\n        if (options.proxy && options.proxyCredentials) {\n            proxyToCredentialsMap[options.proxy] = options.proxyCredentials;\n        }\n        window.on(\"ready-to-show\", () => {\n            if (readyToShowWindowsIds.includes(window.id)) {\n                readyToShowWindowsIds = readyToShowWindowsIds.filter((value) => value !== window.id);\n            }\n            else {\n                readyToShowWindowsIds.push(window.id);\n            }\n        });\n        lastOptions = options;\n        window.on(\"closed\", (sender) => {\n            for (let index = 0; index < windows.length; index++) {\n                const windowItem = windows[index];\n                try {\n                    windowItem.id;\n                }\n                catch (error) {\n                    if (error.message === \"Object has been destroyed\") {\n                        windows.splice(index, 1);\n                        const ids = [];\n                        windows.forEach((x) => ids.push(x.id));\n                        electronSocket.emit(\"BrowserWindowClosed\", ids);\n                    }\n                }\n            }\n        });\n        app.on(\"activate\", () => {\n            // On macOS it's common to re-create a window in the app when the\n            // dock icon is clicked and there are no other windows open.\n            if (window === null && lastOptions) {\n                window = new electron_1.BrowserWindow(lastOptions);\n            }\n        });\n        if (loadUrl) {\n            window.loadURL(loadUrl);\n        }\n        if (app.commandLine.hasSwitch(\"clear-cache\") &&\n            app.commandLine.getSwitchValue(\"clear-cache\")) {\n            window.webContents.session.clearCache();\n            console.log(\"auto clear-cache active for new window.\");\n        }\n        // set main window url\n        if (app[\"mainWindowURL\"] == undefined || app[\"mainWindowURL\"] == \"\") {\n            app[\"mainWindowURL\"] = loadUrl;\n            app[\"mainWindow\"] = window;\n        }\n        windows.push(window);\n        electronSocket.emit(\"BrowserWindowCreated\", window.id);\n    });\n    socket.on(\"browserWindowDestroy\", (id) => {\n        getWindowById(id).destroy();\n    });\n    socket.on(\"browserWindowClose\", (id) => {\n        getWindowById(id).close();\n    });\n    socket.on(\"browserWindowFocus\", (id) => {\n        getWindowById(id).focus();\n    });\n    socket.on(\"browserWindowBlur\", (id) => {\n        getWindowById(id).blur();\n    });\n    socket.on(\"browserWindowIsFocused\", (id) => {\n        const isFocused = getWindowById(id).isFocused();\n        electronSocket.emit(\"browserWindow-isFocused-completed\", isFocused);\n    });\n    socket.on(\"browserWindowIsDestroyed\", (id) => {\n        const isDestroyed = getWindowById(id).isDestroyed();\n        electronSocket.emit(\"browserWindow-isDestroyed-completed\", isDestroyed);\n    });\n    socket.on(\"browserWindowShow\", (id) => {\n        getWindowById(id).show();\n    });\n    socket.on(\"browserWindowShowInactive\", (id) => {\n        getWindowById(id).showInactive();\n    });\n    socket.on(\"browserWindowHide\", (id) => {\n        getWindowById(id).hide();\n    });\n    socket.on(\"browserWindowIsVisible\", (id) => {\n        const isVisible = getWindowById(id).isVisible();\n        electronSocket.emit(\"browserWindow-isVisible-completed\", isVisible);\n    });\n    socket.on(\"browserWindowIsModal\", (id) => {\n        const isModal = getWindowById(id).isModal();\n        electronSocket.emit(\"browserWindow-isModal-completed\", isModal);\n    });\n    socket.on(\"browserWindowMaximize\", (id) => {\n        getWindowById(id).maximize();\n    });\n    socket.on(\"browserWindowUnmaximize\", (id) => {\n        getWindowById(id).unmaximize();\n    });\n    socket.on(\"browserWindowIsMaximized\", (id) => {\n        const isMaximized = getWindowById(id).isMaximized();\n        electronSocket.emit(\"browserWindow-isMaximized-completed\", isMaximized);\n    });\n    socket.on(\"browserWindowMinimize\", (id) => {\n        getWindowById(id).minimize();\n    });\n    socket.on(\"browserWindowRestore\", (id) => {\n        getWindowById(id).restore();\n    });\n    socket.on(\"browserWindowIsMinimized\", (id) => {\n        const isMinimized = getWindowById(id).isMinimized();\n        electronSocket.emit(\"browserWindow-isMinimized-completed\", isMinimized);\n    });\n    socket.on(\"browserWindowSetFullScreen\", (id, fullscreen) => {\n        getWindowById(id).setFullScreen(fullscreen);\n    });\n    socket.on(\"browserWindowIsFullScreen\", (id) => {\n        const isFullScreen = getWindowById(id).isFullScreen();\n        electronSocket.emit(\"browserWindow-isFullScreen-completed\", isFullScreen);\n    });\n    socket.on(\"browserWindowSetAspectRatio\", (id, aspectRatio, extraSize) => {\n        getWindowById(id).setAspectRatio(aspectRatio, extraSize);\n    });\n    socket.on(\"browserWindowPreviewFile\", (id, path, displayname) => {\n        getWindowById(id).previewFile(path, displayname);\n    });\n    socket.on(\"browserWindowCloseFilePreview\", (id) => {\n        getWindowById(id).closeFilePreview();\n    });\n    socket.on(\"browserWindowSetBounds\", (id, bounds, animate) => {\n        getWindowById(id).setBounds(bounds, animate);\n    });\n    socket.on(\"browserWindowGetBounds\", (id) => {\n        const rectangle = getWindowById(id).getBounds();\n        electronSocket.emit(\"browserWindow-getBounds-completed\", rectangle);\n    });\n    socket.on(\"browserWindowSetContentBounds\", (id, bounds, animate) => {\n        getWindowById(id).setContentBounds(bounds, animate);\n    });\n    socket.on(\"browserWindowGetContentBounds\", (id) => {\n        const rectangle = getWindowById(id).getContentBounds();\n        electronSocket.emit(\"browserWindow-getContentBounds-completed\", rectangle);\n    });\n    socket.on(\"browserWindowSetSize\", (id, width, height, animate) => {\n        getWindowById(id).setSize(width, height, animate);\n    });\n    socket.on(\"browserWindowGetSize\", (id) => {\n        const size = getWindowById(id).getSize();\n        electronSocket.emit(\"browserWindow-getSize-completed\", size);\n    });\n    socket.on(\"browserWindowSetContentSize\", (id, width, height, animate) => {\n        getWindowById(id).setContentSize(width, height, animate);\n    });\n    socket.on(\"browserWindowGetContentSize\", (id) => {\n        const size = getWindowById(id).getContentSize();\n        electronSocket.emit(\"browserWindow-getContentSize-completed\", size);\n    });\n    socket.on(\"browserWindowSetMinimumSize\", (id, width, height) => {\n        getWindowById(id).setMinimumSize(width, height);\n    });\n    socket.on(\"browserWindowGetMinimumSize\", (id) => {\n        const size = getWindowById(id).getMinimumSize();\n        electronSocket.emit(\"browserWindow-getMinimumSize-completed\", size);\n    });\n    socket.on(\"browserWindowSetMaximumSize\", (id, width, height) => {\n        getWindowById(id).setMaximumSize(width, height);\n    });\n    socket.on(\"browserWindowGetMaximumSize\", (id) => {\n        const size = getWindowById(id).getMaximumSize();\n        electronSocket.emit(\"browserWindow-getMaximumSize-completed\", size);\n    });\n    socket.on(\"browserWindowSetResizable\", (id, resizable) => {\n        getWindowById(id).setResizable(resizable);\n    });\n    socket.on(\"browserWindowIsResizable\", (id) => {\n        const resizable = getWindowById(id).isResizable();\n        electronSocket.emit(\"browserWindow-isResizable-completed\", resizable);\n    });\n    socket.on(\"browserWindowSetMovable\", (id, movable) => {\n        getWindowById(id).setMovable(movable);\n    });\n    socket.on(\"browserWindowIsMovable\", (id) => {\n        const movable = getWindowById(id).isMovable();\n        electronSocket.emit(\"browserWindow-isMovable-completed\", movable);\n    });\n    socket.on(\"browserWindowSetMinimizable\", (id, minimizable) => {\n        getWindowById(id).setMinimizable(minimizable);\n    });\n    socket.on(\"browserWindowIsMinimizable\", (id) => {\n        const minimizable = getWindowById(id).isMinimizable();\n        electronSocket.emit(\"browserWindow-isMinimizable-completed\", minimizable);\n    });\n    socket.on(\"browserWindowSetMaximizable\", (id, maximizable) => {\n        getWindowById(id).setMaximizable(maximizable);\n    });\n    socket.on(\"browserWindowIsMaximizable\", (id) => {\n        const maximizable = getWindowById(id).isMaximizable();\n        electronSocket.emit(\"browserWindow-isMaximizable-completed\", maximizable);\n    });\n    socket.on(\"browserWindowSetFullScreenable\", (id, fullscreenable) => {\n        getWindowById(id).setFullScreenable(fullscreenable);\n    });\n    socket.on(\"browserWindowIsFullScreenable\", (id) => {\n        const fullscreenable = getWindowById(id).isFullScreenable();\n        electronSocket.emit(\"browserWindow-isFullScreenable-completed\", fullscreenable);\n    });\n    socket.on(\"browserWindowSetClosable\", (id, closable) => {\n        getWindowById(id).setClosable(closable);\n    });\n    socket.on(\"browserWindowIsClosable\", (id) => {\n        const closable = getWindowById(id).isClosable();\n        electronSocket.emit(\"browserWindow-isClosable-completed\", closable);\n    });\n    socket.on(\"browserWindowSetAlwaysOnTop\", (id, flag, level, relativeLevel) => {\n        getWindowById(id).setAlwaysOnTop(flag, level, relativeLevel);\n    });\n    socket.on(\"browserWindowIsAlwaysOnTop\", (id) => {\n        const isAlwaysOnTop = getWindowById(id).isAlwaysOnTop();\n        electronSocket.emit(\"browserWindow-isAlwaysOnTop-completed\", isAlwaysOnTop);\n    });\n    socket.on(\"browserWindowCenter\", (id) => {\n        getWindowById(id).center();\n    });\n    socket.on(\"browserWindowSetPosition\", (id, x, y, animate) => {\n        getWindowById(id).setPosition(x, y, animate);\n    });\n    socket.on(\"browserWindowGetPosition\", (id) => {\n        const position = getWindowById(id).getPosition();\n        electronSocket.emit(\"browserWindow-getPosition-completed\", position);\n    });\n    socket.on(\"browserWindowSetTitle\", (id, title) => {\n        getWindowById(id).setTitle(title);\n    });\n    socket.on(\"browserWindowGetTitle\", (id) => {\n        const title = getWindowById(id).getTitle();\n        electronSocket.emit(\"browserWindow-getTitle-completed\", title);\n    });\n    socket.on(\"browserWindowSetTitle\", (id, title) => {\n        getWindowById(id).setTitle(title);\n    });\n    socket.on(\"browserWindowSetSheetOffset\", (id, offsetY, offsetX) => {\n        if (offsetX) {\n            getWindowById(id).setSheetOffset(offsetY, offsetX);\n        }\n        else {\n            getWindowById(id).setSheetOffset(offsetY);\n        }\n    });\n    socket.on(\"browserWindowFlashFrame\", (id, flag) => {\n        getWindowById(id).flashFrame(flag);\n    });\n    socket.on(\"browserWindowSetSkipTaskbar\", (id, skip) => {\n        getWindowById(id).setSkipTaskbar(skip);\n    });\n    socket.on(\"browserWindowSetKiosk\", (id, flag) => {\n        getWindowById(id).setKiosk(flag);\n    });\n    socket.on(\"browserWindowIsKiosk\", (id) => {\n        const isKiosk = getWindowById(id).isKiosk();\n        electronSocket.emit(\"browserWindow-isKiosk-completed\", isKiosk);\n    });\n    socket.on(\"browserWindowGetNativeWindowHandle\", (id) => {\n        const nativeWindowHandle = getWindowById(id)\n            .getNativeWindowHandle()\n            .readInt32LE(0)\n            .toString(16);\n        electronSocket.emit(\"browserWindow-getNativeWindowHandle-completed\", nativeWindowHandle);\n    });\n    socket.on(\"browserWindowSetRepresentedFilename\", (id, filename) => {\n        const win = getWindowById(id);\n        try {\n            if (win && typeof win.setRepresentedFilename === \"function\") {\n                win.setRepresentedFilename(filename);\n            }\n        }\n        catch (e) {\n            console.warn(\"setRepresentedFilename failed (likely unsupported platform):\", e);\n        }\n    });\n    socket.on(\"browserWindowGetRepresentedFilename\", (id) => {\n        const win = getWindowById(id);\n        let pathname = \"\";\n        try {\n            if (win && typeof win.getRepresentedFilename === \"function\") {\n                pathname = win.getRepresentedFilename() || \"\";\n            }\n        }\n        catch (e) {\n            console.warn(\"getRepresentedFilename failed (likely unsupported platform):\", e);\n        }\n        electronSocket.emit(\"browserWindow-getRepresentedFilename-completed\", pathname);\n    });\n    socket.on(\"browserWindowSetDocumentEdited\", (id, edited) => {\n        getWindowById(id).setDocumentEdited(edited);\n    });\n    socket.on(\"browserWindowIsDocumentEdited\", (id) => {\n        const edited = getWindowById(id).isDocumentEdited();\n        electronSocket.emit(\"browserWindow-isDocumentEdited-completed\", edited);\n    });\n    socket.on(\"browserWindowFocusOnWebView\", (id) => {\n        getWindowById(id).focusOnWebView();\n    });\n    socket.on(\"browserWindowBlurWebView\", (id) => {\n        getWindowById(id).blurWebView();\n    });\n    socket.on(\"browserWindowLoadURL\", (id, url, options) => {\n        getWindowById(id).loadURL(url, options);\n    });\n    socket.on(\"browserWindowReload\", (id) => {\n        getWindowById(id).reload();\n    });\n    socket.on(\"browserWindowSetMenu\", (id, menuItems) => {\n        let menu = null;\n        if (menuItems) {\n            menu = electron_1.Menu.buildFromTemplate(menuItems);\n            addMenuItemClickConnector(menu.items, (id) => {\n                electronSocket.emit(\"windowMenuItemClicked\", id);\n            });\n        }\n        getWindowById(id).setMenu(menu);\n    });\n    socket.on(\"browserWindowRemoveMenu\", (id) => {\n        getWindowById(id).removeMenu();\n    });\n    function addMenuItemClickConnector(menuItems, callback) {\n        menuItems.forEach((item) => {\n            if (item.submenu && item.submenu.items.length > 0) {\n                addMenuItemClickConnector(item.submenu.items, callback);\n            }\n            if (\"id\" in item && item.id) {\n                item.click = () => {\n                    callback(item.id);\n                };\n            }\n        });\n    }\n    socket.on(\"browserWindowSetProgressBar\", (id, progress) => {\n        getWindowById(id).setProgressBar(progress);\n    });\n    socket.on(\"browserWindowSetProgressBar\", (id, progress, options) => {\n        getWindowById(id).setProgressBar(progress, options);\n    });\n    socket.on(\"browserWindowSetHasShadow\", (id, hasShadow) => {\n        getWindowById(id).setHasShadow(hasShadow);\n    });\n    socket.on(\"browserWindowHasShadow\", (id) => {\n        const hasShadow = getWindowById(id).hasShadow();\n        electronSocket.emit(\"browserWindow-hasShadow-completed\", hasShadow);\n    });\n    socket.on(\"browserWindowSetThumbarButtons\", (id, thumbarButtons) => {\n        thumbarButtons.forEach((thumbarButton) => {\n            const originalIconPath = thumbarButton.icon.toString();\n            const path = require(\"path\");\n            const fs = require(\"fs\");\n            let imagePath = originalIconPath;\n            if (!path.isAbsolute(originalIconPath)) {\n                imagePath = path.join(__dirname.replace(\"api\", \"\"), \"bin\", originalIconPath);\n            }\n            const { nativeImage } = require(\"electron\");\n            if (fs.existsSync(imagePath)) {\n                thumbarButton.icon = nativeImage.createFromPath(imagePath);\n            }\n            else {\n                // Fallback to empty image to avoid failure\n                thumbarButton.icon = nativeImage.createEmpty();\n            }\n            thumbarButton.click = () => {\n                electronSocket.emit(\"thumbarButtonClicked\", thumbarButton[\"id\"]);\n            };\n        });\n        const success = getWindowById(id).setThumbarButtons(thumbarButtons);\n        electronSocket.emit(\"browserWindowSetThumbarButtons-completed\", success);\n    });\n    socket.on(\"browserWindowSetThumbnailClip\", (id, rectangle) => {\n        getWindowById(id).setThumbnailClip(rectangle);\n    });\n    socket.on(\"browserWindowSetThumbnailToolTip\", (id, toolTip) => {\n        getWindowById(id).setThumbnailToolTip(toolTip);\n    });\n    socket.on(\"browserWindowSetAppDetails\", (id, options) => {\n        getWindowById(id).setAppDetails(options);\n    });\n    socket.on(\"browserWindowShowDefinitionForSelection\", (id) => {\n        getWindowById(id).showDefinitionForSelection();\n    });\n    socket.on(\"browserWindowSetAutoHideMenuBar\", (id, hide) => {\n        getWindowById(id).setAutoHideMenuBar(hide);\n    });\n    socket.on(\"browserWindowIsMenuBarAutoHide\", (id) => {\n        const isMenuBarAutoHide = getWindowById(id).isMenuBarAutoHide();\n        electronSocket.emit(\"browserWindow-isMenuBarAutoHide-completed\", isMenuBarAutoHide);\n    });\n    socket.on(\"browserWindowSetMenuBarVisibility\", (id, visible) => {\n        getWindowById(id).setMenuBarVisibility(visible);\n    });\n    socket.on(\"browserWindowIsMenuBarVisible\", (id) => {\n        const isMenuBarVisible = getWindowById(id).isMenuBarVisible();\n        electronSocket.emit(\"browserWindow-isMenuBarVisible-completed\", isMenuBarVisible);\n    });\n    socket.on(\"browserWindowSetVisibleOnAllWorkspaces\", (id, visible) => {\n        getWindowById(id).setVisibleOnAllWorkspaces(visible);\n    });\n    socket.on(\"browserWindowIsVisibleOnAllWorkspaces\", (id) => {\n        const isVisibleOnAllWorkspaces = getWindowById(id).isVisibleOnAllWorkspaces();\n        electronSocket.emit(\"browserWindow-isVisibleOnAllWorkspaces-completed\", isVisibleOnAllWorkspaces);\n    });\n    socket.on(\"browserWindowSetIgnoreMouseEvents\", (id, ignore) => {\n        getWindowById(id).setIgnoreMouseEvents(ignore);\n    });\n    socket.on(\"browserWindowSetContentProtection\", (id, enable) => {\n        getWindowById(id).setContentProtection(enable);\n    });\n    socket.on(\"browserWindowSetFocusable\", (id, focusable) => {\n        getWindowById(id).setFocusable(focusable);\n    });\n    socket.on(\"browserWindowSetParentWindow\", (id, parent) => {\n        const child = getWindowById(id);\n        if (!parent) {\n            // Clear parent: make this window top-level\n            child.setParentWindow(null);\n            return;\n        }\n        const browserWindow = electron_1.BrowserWindow.fromId(parent.id);\n        child.setParentWindow(browserWindow);\n    });\n    socket.on(\"browserWindowGetParentWindow\", (id) => {\n        const browserWindow = getWindowById(id).getParentWindow();\n        electronSocket.emit(\"browserWindow-getParentWindow-completed\", browserWindow.id);\n    });\n    socket.on(\"browserWindowGetChildWindows\", (id) => {\n        const browserWindows = getWindowById(id).getChildWindows();\n        const ids = [];\n        browserWindows.forEach((x) => {\n            ids.push(x.id);\n        });\n        electronSocket.emit(\"browserWindow-getChildWindows-completed\", ids);\n    });\n    socket.on(\"browserWindowSetAutoHideCursor\", (id, autoHide) => {\n        getWindowById(id).setAutoHideCursor(autoHide);\n    });\n    socket.on(\"browserWindowSetVibrancy\", (id, type) => {\n        getWindowById(id).setVibrancy(type);\n    });\n    socket.on(\"browserWindow-setBrowserView\", (id, browserViewId) => {\n        getWindowById(id).setBrowserView((0, browserView_1.browserViewMediateService)(browserViewId));\n    });\n    function getWindowById(id) {\n        for (let index = 0; index < windows.length; index++) {\n            const element = windows[index];\n            if (element.id === id) {\n                return element;\n            }\n        }\n    }\n};\n//# sourceMappingURL=browserWindows.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/browserWindows.ts",
    "content": "import * as path from \"path\";\nimport type { Socket } from \"net\";\nimport { BrowserWindow, Menu } from \"electron\";\n\nimport { browserViewMediateService } from \"./browserView\";\n\nconst windows: Electron.BrowserWindow[] = (global[\"browserWindows\"] =\n  global[\"browserWindows\"] || []) as Electron.BrowserWindow[];\nlet readyToShowWindowsIds: number[] = [];\n\nlet window;\nlet lastOptions;\nlet electronSocket;\n\nconst proxyToCredentialsMap: { [proxy: string]: string } = (global[\n  \"proxyToCredentialsMap\"\n] = global[\"proxyToCredentialsMap\"] || []) as { [proxy: string]: string };\n\nexport = (socket: Socket, app: Electron.App) => {\n  electronSocket = socket;\n\n  app.on(\"login\", (event, webContents, request, authInfo, callback) => {\n    if (authInfo.isProxy) {\n      let proxy = `${authInfo.host}:${authInfo.port}`;\n      if (\n        proxy in proxyToCredentialsMap &&\n        proxyToCredentialsMap[proxy].split(\":\").length === 2\n      ) {\n        event.preventDefault();\n        let user = proxyToCredentialsMap[proxy].split(\":\")[0];\n        let pass = proxyToCredentialsMap[proxy].split(\":\")[1];\n        callback(user, pass);\n      }\n    }\n  });\n\n  socket.on(\"register-browserWindow-ready-to-show\", (id) => {\n    if (readyToShowWindowsIds.includes(id)) {\n      readyToShowWindowsIds = readyToShowWindowsIds.filter(\n        (value) => value !== id,\n      );\n      electronSocket.emit(\"browserWindow-ready-to-show\" + id);\n    }\n\n    getWindowById(id).on(\"ready-to-show\", () => {\n      readyToShowWindowsIds.push(id);\n      electronSocket.emit(\"browserWindow-ready-to-show\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-page-title-updated\", (id) => {\n    getWindowById(id).on(\"page-title-updated\", (event, title) => {\n      electronSocket.emit(\"browserWindow-page-title-updated\" + id, title);\n    });\n  });\n\n  socket.on(\"register-browserWindow-close\", (id) => {\n    getWindowById(id).on(\"close\", () => {\n      electronSocket.emit(\"browserWindow-close\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-closed\", (id) => {\n    getWindowById(id).on(\"closed\", () => {\n      electronSocket.emit(\"browserWindow-closed\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-session-end\", (id) => {\n    getWindowById(id).on(\"session-end\", () => {\n      electronSocket.emit(\"browserWindow-session-end\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-unresponsive\", (id) => {\n    getWindowById(id).on(\"unresponsive\", () => {\n      electronSocket.emit(\"browserWindow-unresponsive\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-responsive\", (id) => {\n    getWindowById(id).on(\"responsive\", () => {\n      electronSocket.emit(\"browserWindow-responsive\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-blur\", (id) => {\n    getWindowById(id).on(\"blur\", () => {\n      electronSocket.emit(\"browserWindow-blur\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-focus\", (id) => {\n    getWindowById(id).on(\"focus\", () => {\n      electronSocket.emit(\"browserWindow-focus\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-show\", (id) => {\n    getWindowById(id).on(\"show\", () => {\n      electronSocket.emit(\"browserWindow-show\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-hide\", (id) => {\n    getWindowById(id).on(\"hide\", () => {\n      electronSocket.emit(\"browserWindow-hide\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-maximize\", (id) => {\n    getWindowById(id).on(\"maximize\", () => {\n      electronSocket.emit(\"browserWindow-maximize\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-unmaximize\", (id) => {\n    getWindowById(id).on(\"unmaximize\", () => {\n      electronSocket.emit(\"browserWindow-unmaximize\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-minimize\", (id) => {\n    getWindowById(id).on(\"minimize\", () => {\n      electronSocket.emit(\"browserWindow-minimize\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-restore\", (id) => {\n    getWindowById(id).on(\"restore\", () => {\n      electronSocket.emit(\"browserWindow-restore\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-resize\", (id) => {\n    getWindowById(id).on(\"resize\", () => {\n      electronSocket.emit(\"browserWindow-resize\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-move\", (id) => {\n    getWindowById(id).on(\"move\", () => {\n      electronSocket.emit(\"browserWindow-move\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-bounds-changed\", (id) => {\n    const window = getWindowById(id);\n    const cb = () =>\n      electronSocket.emit(\n        \"browserWindow-bounds-changed\" + id,\n        window.getBounds(),\n      );\n    window.on(\"resize\", cb);\n    window.on(\"move\", cb);\n  });\n\n  socket.on(\"register-browserWindow-moved\", (id) => {\n    getWindowById(id).on(\"moved\", () => {\n      electronSocket.emit(\"browserWindow-moved\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-enter-full-screen\", (id) => {\n    getWindowById(id).on(\"enter-full-screen\", () => {\n      electronSocket.emit(\"browserWindow-enter-full-screen\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-leave-full-screen\", (id) => {\n    getWindowById(id).on(\"leave-full-screen\", () => {\n      electronSocket.emit(\"browserWindow-leave-full-screen\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-enter-html-full-screen\", (id) => {\n    getWindowById(id).on(\"enter-html-full-screen\", () => {\n      electronSocket.emit(\"browserWindow-enter-html-full-screen\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-leave-html-full-screen\", (id) => {\n    getWindowById(id).on(\"leave-html-full-screen\", () => {\n      electronSocket.emit(\"browserWindow-leave-html-full-screen\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-app-command\", (id) => {\n    getWindowById(id).on(\"app-command\", (event, command) => {\n      electronSocket.emit(\"browserWindow-app-command\" + id, command);\n    });\n  });\n\n  socket.on(\"register-browserWindow-swipe\", (id) => {\n    getWindowById(id).on(\"swipe\", (event, direction) => {\n      electronSocket.emit(\"browserWindow-swipe\" + id, direction);\n    });\n  });\n\n  socket.on(\"register-browserWindow-sheet-begin\", (id) => {\n    getWindowById(id).on(\"sheet-begin\", () => {\n      electronSocket.emit(\"browserWindow-sheet-begin\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-sheet-end\", (id) => {\n    getWindowById(id).on(\"sheet-end\", () => {\n      electronSocket.emit(\"browserWindow-sheet-end\" + id);\n    });\n  });\n\n  socket.on(\"register-browserWindow-new-window-for-tab\", (id) => {\n    getWindowById(id).on(\"new-window-for-tab\", () => {\n      electronSocket.emit(\"browserWindow-new-window-for-tab\" + id);\n    });\n  });\n\n  socket.on(\"createBrowserWindow\", (options, loadUrl) => {\n    if (\n      options.webPreferences &&\n      !(\"nodeIntegration\" in options.webPreferences)\n    ) {\n      options = {\n        ...options,\n        webPreferences: {\n          ...options.webPreferences,\n          nodeIntegration: true,\n          contextIsolation: false,\n        },\n      };\n    } else if (!options.webPreferences) {\n      options = {\n        ...options,\n        webPreferences: { nodeIntegration: true, contextIsolation: false },\n      };\n    }\n\n    if (options.isRunningBlazor) {\n      options.webPreferences[\"preload\"] = path.join(\n        __dirname,\n        \"..\",\n        \"scripts\",\n        \"blazor-preload.js\",\n      );\n    }\n\n    delete options.isRunningBlazor;\n\n    // we dont want to recreate the window when watch is ready.\n    if (\n      app.commandLine.hasSwitch(\"watch\") &&\n      app[\"mainWindowURL\"] === loadUrl\n    ) {\n      window = app[\"mainWindow\"];\n      if (window) {\n        window.reload();\n        windows.push(window);\n        electronSocket.emit(\"BrowserWindowCreated\", window.id);\n        return;\n      }\n    } else {\n      window = new BrowserWindow(options);\n    }\n\n    if (options.proxy) {\n      window.webContents.session.setProxy({ proxyRules: options.proxy });\n    }\n\n    if (options.proxy && options.proxyCredentials) {\n      proxyToCredentialsMap[options.proxy] = options.proxyCredentials;\n    }\n\n    window.on(\"ready-to-show\", () => {\n      if (readyToShowWindowsIds.includes(window.id)) {\n        readyToShowWindowsIds = readyToShowWindowsIds.filter(\n          (value) => value !== window.id,\n        );\n      } else {\n        readyToShowWindowsIds.push(window.id);\n      }\n    });\n\n    lastOptions = options;\n\n    window.on(\"closed\", (sender) => {\n      for (let index = 0; index < windows.length; index++) {\n        const windowItem = windows[index];\n        try {\n          windowItem.id;\n        } catch (error) {\n          if (error.message === \"Object has been destroyed\") {\n            windows.splice(index, 1);\n\n            const ids = [];\n            windows.forEach((x) => ids.push(x.id));\n            electronSocket.emit(\"BrowserWindowClosed\", ids);\n          }\n        }\n      }\n    });\n\n    app.on(\"activate\", () => {\n      // On macOS it's common to re-create a window in the app when the\n      // dock icon is clicked and there are no other windows open.\n      if (window === null && lastOptions) {\n        window = new BrowserWindow(lastOptions);\n      }\n    });\n\n    if (loadUrl) {\n      window.loadURL(loadUrl);\n    }\n\n    if (\n      app.commandLine.hasSwitch(\"clear-cache\") &&\n      app.commandLine.getSwitchValue(\"clear-cache\")\n    ) {\n      window.webContents.session.clearCache();\n      console.log(\"auto clear-cache active for new window.\");\n    }\n\n    // set main window url\n    if (app[\"mainWindowURL\"] == undefined || app[\"mainWindowURL\"] == \"\") {\n      app[\"mainWindowURL\"] = loadUrl;\n      app[\"mainWindow\"] = window;\n    }\n\n    windows.push(window);\n    electronSocket.emit(\"BrowserWindowCreated\", window.id);\n  });\n\n  socket.on(\"browserWindowDestroy\", (id) => {\n    getWindowById(id).destroy();\n  });\n\n  socket.on(\"browserWindowClose\", (id) => {\n    getWindowById(id).close();\n  });\n\n  socket.on(\"browserWindowFocus\", (id) => {\n    getWindowById(id).focus();\n  });\n\n  socket.on(\"browserWindowBlur\", (id) => {\n    getWindowById(id).blur();\n  });\n\n  socket.on(\"browserWindowIsFocused\", (id) => {\n    const isFocused = getWindowById(id).isFocused();\n\n    electronSocket.emit(\"browserWindow-isFocused-completed\", isFocused);\n  });\n\n  socket.on(\"browserWindowIsDestroyed\", (id) => {\n    const isDestroyed = getWindowById(id).isDestroyed();\n\n    electronSocket.emit(\"browserWindow-isDestroyed-completed\", isDestroyed);\n  });\n\n  socket.on(\"browserWindowShow\", (id) => {\n    getWindowById(id).show();\n  });\n\n  socket.on(\"browserWindowShowInactive\", (id) => {\n    getWindowById(id).showInactive();\n  });\n\n  socket.on(\"browserWindowHide\", (id) => {\n    getWindowById(id).hide();\n  });\n\n  socket.on(\"browserWindowIsVisible\", (id) => {\n    const isVisible = getWindowById(id).isVisible();\n\n    electronSocket.emit(\"browserWindow-isVisible-completed\", isVisible);\n  });\n\n  socket.on(\"browserWindowIsModal\", (id) => {\n    const isModal = getWindowById(id).isModal();\n\n    electronSocket.emit(\"browserWindow-isModal-completed\", isModal);\n  });\n\n  socket.on(\"browserWindowMaximize\", (id) => {\n    getWindowById(id).maximize();\n  });\n\n  socket.on(\"browserWindowUnmaximize\", (id) => {\n    getWindowById(id).unmaximize();\n  });\n\n  socket.on(\"browserWindowIsMaximized\", (id) => {\n    const isMaximized = getWindowById(id).isMaximized();\n\n    electronSocket.emit(\"browserWindow-isMaximized-completed\", isMaximized);\n  });\n\n  socket.on(\"browserWindowMinimize\", (id) => {\n    getWindowById(id).minimize();\n  });\n\n  socket.on(\"browserWindowRestore\", (id) => {\n    getWindowById(id).restore();\n  });\n\n  socket.on(\"browserWindowIsMinimized\", (id) => {\n    const isMinimized = getWindowById(id).isMinimized();\n\n    electronSocket.emit(\"browserWindow-isMinimized-completed\", isMinimized);\n  });\n\n  socket.on(\"browserWindowSetFullScreen\", (id, fullscreen) => {\n    getWindowById(id).setFullScreen(fullscreen);\n  });\n\n  socket.on(\"browserWindowIsFullScreen\", (id) => {\n    const isFullScreen = getWindowById(id).isFullScreen();\n\n    electronSocket.emit(\"browserWindow-isFullScreen-completed\", isFullScreen);\n  });\n\n  socket.on(\"browserWindowSetAspectRatio\", (id, aspectRatio, extraSize) => {\n    getWindowById(id).setAspectRatio(aspectRatio, extraSize);\n  });\n\n  socket.on(\"browserWindowPreviewFile\", (id, path, displayname) => {\n    getWindowById(id).previewFile(path, displayname);\n  });\n\n  socket.on(\"browserWindowCloseFilePreview\", (id) => {\n    getWindowById(id).closeFilePreview();\n  });\n\n  socket.on(\"browserWindowSetBounds\", (id, bounds, animate) => {\n    getWindowById(id).setBounds(bounds, animate);\n  });\n\n  socket.on(\"browserWindowGetBounds\", (id) => {\n    const rectangle = getWindowById(id).getBounds();\n\n    electronSocket.emit(\"browserWindow-getBounds-completed\", rectangle);\n  });\n\n  socket.on(\"browserWindowSetContentBounds\", (id, bounds, animate) => {\n    getWindowById(id).setContentBounds(bounds, animate);\n  });\n\n  socket.on(\"browserWindowGetContentBounds\", (id) => {\n    const rectangle = getWindowById(id).getContentBounds();\n\n    electronSocket.emit(\"browserWindow-getContentBounds-completed\", rectangle);\n  });\n\n  socket.on(\"browserWindowSetSize\", (id, width, height, animate) => {\n    getWindowById(id).setSize(width, height, animate);\n  });\n\n  socket.on(\"browserWindowGetSize\", (id) => {\n    const size = getWindowById(id).getSize();\n\n    electronSocket.emit(\"browserWindow-getSize-completed\", size);\n  });\n\n  socket.on(\"browserWindowSetContentSize\", (id, width, height, animate) => {\n    getWindowById(id).setContentSize(width, height, animate);\n  });\n\n  socket.on(\"browserWindowGetContentSize\", (id) => {\n    const size = getWindowById(id).getContentSize();\n\n    electronSocket.emit(\"browserWindow-getContentSize-completed\", size);\n  });\n\n  socket.on(\"browserWindowSetMinimumSize\", (id, width, height) => {\n    getWindowById(id).setMinimumSize(width, height);\n  });\n\n  socket.on(\"browserWindowGetMinimumSize\", (id) => {\n    const size = getWindowById(id).getMinimumSize();\n\n    electronSocket.emit(\"browserWindow-getMinimumSize-completed\", size);\n  });\n\n  socket.on(\"browserWindowSetMaximumSize\", (id, width, height) => {\n    getWindowById(id).setMaximumSize(width, height);\n  });\n\n  socket.on(\"browserWindowGetMaximumSize\", (id) => {\n    const size = getWindowById(id).getMaximumSize();\n\n    electronSocket.emit(\"browserWindow-getMaximumSize-completed\", size);\n  });\n\n  socket.on(\"browserWindowSetResizable\", (id, resizable) => {\n    getWindowById(id).setResizable(resizable);\n  });\n\n  socket.on(\"browserWindowIsResizable\", (id) => {\n    const resizable = getWindowById(id).isResizable();\n\n    electronSocket.emit(\"browserWindow-isResizable-completed\", resizable);\n  });\n\n  socket.on(\"browserWindowSetMovable\", (id, movable) => {\n    getWindowById(id).setMovable(movable);\n  });\n\n  socket.on(\"browserWindowIsMovable\", (id) => {\n    const movable = getWindowById(id).isMovable();\n\n    electronSocket.emit(\"browserWindow-isMovable-completed\", movable);\n  });\n\n  socket.on(\"browserWindowSetMinimizable\", (id, minimizable) => {\n    getWindowById(id).setMinimizable(minimizable);\n  });\n\n  socket.on(\"browserWindowIsMinimizable\", (id) => {\n    const minimizable = getWindowById(id).isMinimizable();\n\n    electronSocket.emit(\"browserWindow-isMinimizable-completed\", minimizable);\n  });\n\n  socket.on(\"browserWindowSetMaximizable\", (id, maximizable) => {\n    getWindowById(id).setMaximizable(maximizable);\n  });\n\n  socket.on(\"browserWindowIsMaximizable\", (id) => {\n    const maximizable = getWindowById(id).isMaximizable();\n\n    electronSocket.emit(\"browserWindow-isMaximizable-completed\", maximizable);\n  });\n\n  socket.on(\"browserWindowSetFullScreenable\", (id, fullscreenable) => {\n    getWindowById(id).setFullScreenable(fullscreenable);\n  });\n\n  socket.on(\"browserWindowIsFullScreenable\", (id) => {\n    const fullscreenable = getWindowById(id).isFullScreenable();\n\n    electronSocket.emit(\n      \"browserWindow-isFullScreenable-completed\",\n      fullscreenable,\n    );\n  });\n\n  socket.on(\"browserWindowSetClosable\", (id, closable) => {\n    getWindowById(id).setClosable(closable);\n  });\n\n  socket.on(\"browserWindowIsClosable\", (id) => {\n    const closable = getWindowById(id).isClosable();\n\n    electronSocket.emit(\"browserWindow-isClosable-completed\", closable);\n  });\n\n  socket.on(\"browserWindowSetAlwaysOnTop\", (id, flag, level, relativeLevel) => {\n    getWindowById(id).setAlwaysOnTop(flag, level, relativeLevel);\n  });\n\n  socket.on(\"browserWindowIsAlwaysOnTop\", (id) => {\n    const isAlwaysOnTop = getWindowById(id).isAlwaysOnTop();\n\n    electronSocket.emit(\"browserWindow-isAlwaysOnTop-completed\", isAlwaysOnTop);\n  });\n\n  socket.on(\"browserWindowCenter\", (id) => {\n    getWindowById(id).center();\n  });\n\n  socket.on(\"browserWindowSetPosition\", (id, x, y, animate) => {\n    getWindowById(id).setPosition(x, y, animate);\n  });\n\n  socket.on(\"browserWindowGetPosition\", (id) => {\n    const position = getWindowById(id).getPosition();\n\n    electronSocket.emit(\"browserWindow-getPosition-completed\", position);\n  });\n\n  socket.on(\"browserWindowSetTitle\", (id, title) => {\n    getWindowById(id).setTitle(title);\n  });\n\n  socket.on(\"browserWindowGetTitle\", (id) => {\n    const title = getWindowById(id).getTitle();\n\n    electronSocket.emit(\"browserWindow-getTitle-completed\", title);\n  });\n\n  socket.on(\"browserWindowSetTitle\", (id, title) => {\n    getWindowById(id).setTitle(title);\n  });\n\n  socket.on(\"browserWindowSetSheetOffset\", (id, offsetY, offsetX) => {\n    if (offsetX) {\n      getWindowById(id).setSheetOffset(offsetY, offsetX);\n    } else {\n      getWindowById(id).setSheetOffset(offsetY);\n    }\n  });\n\n  socket.on(\"browserWindowFlashFrame\", (id, flag) => {\n    getWindowById(id).flashFrame(flag);\n  });\n\n  socket.on(\"browserWindowSetSkipTaskbar\", (id, skip) => {\n    getWindowById(id).setSkipTaskbar(skip);\n  });\n\n  socket.on(\"browserWindowSetKiosk\", (id, flag) => {\n    getWindowById(id).setKiosk(flag);\n  });\n\n  socket.on(\"browserWindowIsKiosk\", (id) => {\n    const isKiosk = getWindowById(id).isKiosk();\n\n    electronSocket.emit(\"browserWindow-isKiosk-completed\", isKiosk);\n  });\n\n  socket.on(\"browserWindowGetNativeWindowHandle\", (id) => {\n    const nativeWindowHandle = getWindowById(id)\n      .getNativeWindowHandle()\n      .readInt32LE(0)\n      .toString(16);\n    electronSocket.emit(\n      \"browserWindow-getNativeWindowHandle-completed\",\n      nativeWindowHandle,\n    );\n  });\n\n  socket.on(\"browserWindowSetRepresentedFilename\", (id, filename) => {\n    const win = getWindowById(id);\n    try {\n      if (win && typeof win.setRepresentedFilename === \"function\") {\n        win.setRepresentedFilename(filename);\n      }\n    } catch (e) {\n      console.warn(\n        \"setRepresentedFilename failed (likely unsupported platform):\",\n        e,\n      );\n    }\n  });\n\n  socket.on(\"browserWindowGetRepresentedFilename\", (id) => {\n    const win = getWindowById(id);\n    let pathname = \"\";\n    try {\n      if (win && typeof win.getRepresentedFilename === \"function\") {\n        pathname = win.getRepresentedFilename() || \"\";\n      }\n    } catch (e) {\n      console.warn(\n        \"getRepresentedFilename failed (likely unsupported platform):\",\n        e,\n      );\n    }\n    electronSocket.emit(\n      \"browserWindow-getRepresentedFilename-completed\",\n      pathname,\n    );\n  });\n\n  socket.on(\"browserWindowSetDocumentEdited\", (id, edited) => {\n    getWindowById(id).setDocumentEdited(edited);\n  });\n\n  socket.on(\"browserWindowIsDocumentEdited\", (id) => {\n    const edited = getWindowById(id).isDocumentEdited();\n\n    electronSocket.emit(\"browserWindow-isDocumentEdited-completed\", edited);\n  });\n\n  socket.on(\"browserWindowFocusOnWebView\", (id) => {\n    getWindowById(id).focusOnWebView();\n  });\n\n  socket.on(\"browserWindowBlurWebView\", (id) => {\n    getWindowById(id).blurWebView();\n  });\n\n  socket.on(\"browserWindowLoadURL\", (id, url, options) => {\n    getWindowById(id).loadURL(url, options);\n  });\n\n  socket.on(\"browserWindowReload\", (id) => {\n    getWindowById(id).reload();\n  });\n\n  socket.on(\"browserWindowSetMenu\", (id, menuItems) => {\n    let menu = null;\n\n    if (menuItems) {\n      menu = Menu.buildFromTemplate(menuItems);\n\n      addMenuItemClickConnector(menu.items, (id) => {\n        electronSocket.emit(\"windowMenuItemClicked\", id);\n      });\n    }\n\n    getWindowById(id).setMenu(menu);\n  });\n\n  socket.on(\"browserWindowRemoveMenu\", (id) => {\n    getWindowById(id).removeMenu();\n  });\n\n  function addMenuItemClickConnector(menuItems, callback) {\n    menuItems.forEach((item) => {\n      if (item.submenu && item.submenu.items.length > 0) {\n        addMenuItemClickConnector(item.submenu.items, callback);\n      }\n\n      if (\"id\" in item && item.id) {\n        item.click = () => {\n          callback(item.id);\n        };\n      }\n    });\n  }\n\n  socket.on(\"browserWindowSetProgressBar\", (id, progress) => {\n    getWindowById(id).setProgressBar(progress);\n  });\n\n  socket.on(\"browserWindowSetProgressBar\", (id, progress, options) => {\n    getWindowById(id).setProgressBar(progress, options);\n  });\n\n  socket.on(\"browserWindowSetHasShadow\", (id, hasShadow) => {\n    getWindowById(id).setHasShadow(hasShadow);\n  });\n\n  socket.on(\"browserWindowHasShadow\", (id) => {\n    const hasShadow = getWindowById(id).hasShadow();\n\n    electronSocket.emit(\"browserWindow-hasShadow-completed\", hasShadow);\n  });\n\n  socket.on(\n    \"browserWindowSetThumbarButtons\",\n    (id, thumbarButtons: Electron.ThumbarButton[]) => {\n      thumbarButtons.forEach((thumbarButton) => {\n        const originalIconPath = thumbarButton.icon.toString();\n        const path = require(\"path\");\n        const fs = require(\"fs\");\n        let imagePath = originalIconPath;\n        if (!path.isAbsolute(originalIconPath)) {\n          imagePath = path.join(\n            __dirname.replace(\"api\", \"\"),\n            \"bin\",\n            originalIconPath,\n          );\n        }\n        const { nativeImage } = require(\"electron\");\n        if (fs.existsSync(imagePath)) {\n          thumbarButton.icon = nativeImage.createFromPath(imagePath);\n        } else {\n          // Fallback to empty image to avoid failure\n          thumbarButton.icon = nativeImage.createEmpty();\n        }\n        thumbarButton.click = () => {\n          electronSocket.emit(\"thumbarButtonClicked\", thumbarButton[\"id\"]);\n        };\n      });\n\n      const success = getWindowById(id).setThumbarButtons(thumbarButtons);\n      electronSocket.emit(\"browserWindowSetThumbarButtons-completed\", success);\n    },\n  );\n\n  socket.on(\"browserWindowSetThumbnailClip\", (id, rectangle) => {\n    getWindowById(id).setThumbnailClip(rectangle);\n  });\n\n  socket.on(\"browserWindowSetThumbnailToolTip\", (id, toolTip) => {\n    getWindowById(id).setThumbnailToolTip(toolTip);\n  });\n\n  socket.on(\"browserWindowSetAppDetails\", (id, options) => {\n    getWindowById(id).setAppDetails(options);\n  });\n\n  socket.on(\"browserWindowShowDefinitionForSelection\", (id) => {\n    getWindowById(id).showDefinitionForSelection();\n  });\n\n  socket.on(\"browserWindowSetAutoHideMenuBar\", (id, hide) => {\n    getWindowById(id).setAutoHideMenuBar(hide);\n  });\n\n  socket.on(\"browserWindowIsMenuBarAutoHide\", (id) => {\n    const isMenuBarAutoHide = getWindowById(id).isMenuBarAutoHide();\n\n    electronSocket.emit(\n      \"browserWindow-isMenuBarAutoHide-completed\",\n      isMenuBarAutoHide,\n    );\n  });\n\n  socket.on(\"browserWindowSetMenuBarVisibility\", (id, visible) => {\n    getWindowById(id).setMenuBarVisibility(visible);\n  });\n\n  socket.on(\"browserWindowIsMenuBarVisible\", (id) => {\n    const isMenuBarVisible = getWindowById(id).isMenuBarVisible();\n\n    electronSocket.emit(\n      \"browserWindow-isMenuBarVisible-completed\",\n      isMenuBarVisible,\n    );\n  });\n\n  socket.on(\"browserWindowSetVisibleOnAllWorkspaces\", (id, visible) => {\n    getWindowById(id).setVisibleOnAllWorkspaces(visible);\n  });\n\n  socket.on(\"browserWindowIsVisibleOnAllWorkspaces\", (id) => {\n    const isVisibleOnAllWorkspaces =\n      getWindowById(id).isVisibleOnAllWorkspaces();\n\n    electronSocket.emit(\n      \"browserWindow-isVisibleOnAllWorkspaces-completed\",\n      isVisibleOnAllWorkspaces,\n    );\n  });\n\n  socket.on(\"browserWindowSetIgnoreMouseEvents\", (id, ignore) => {\n    getWindowById(id).setIgnoreMouseEvents(ignore);\n  });\n\n  socket.on(\"browserWindowSetContentProtection\", (id, enable) => {\n    getWindowById(id).setContentProtection(enable);\n  });\n\n  socket.on(\"browserWindowSetFocusable\", (id, focusable) => {\n    getWindowById(id).setFocusable(focusable);\n  });\n\n  socket.on(\"browserWindowSetParentWindow\", (id, parent) => {\n    const child = getWindowById(id);\n    if (!parent) {\n      // Clear parent: make this window top-level\n      child.setParentWindow(null);\n      return;\n    }\n    const browserWindow = BrowserWindow.fromId(parent.id);\n    child.setParentWindow(browserWindow);\n  });\n\n  socket.on(\"browserWindowGetParentWindow\", (id) => {\n    const browserWindow = getWindowById(id).getParentWindow();\n\n    electronSocket.emit(\n      \"browserWindow-getParentWindow-completed\",\n      browserWindow.id,\n    );\n  });\n\n  socket.on(\"browserWindowGetChildWindows\", (id) => {\n    const browserWindows = getWindowById(id).getChildWindows();\n\n    const ids = [];\n\n    browserWindows.forEach((x) => {\n      ids.push(x.id);\n    });\n\n    electronSocket.emit(\"browserWindow-getChildWindows-completed\", ids);\n  });\n\n  socket.on(\"browserWindowSetAutoHideCursor\", (id, autoHide) => {\n    getWindowById(id).setAutoHideCursor(autoHide);\n  });\n\n  socket.on(\"browserWindowSetVibrancy\", (id, type) => {\n    getWindowById(id).setVibrancy(type);\n  });\n\n  socket.on(\"browserWindow-setBrowserView\", (id, browserViewId) => {\n    getWindowById(id).setBrowserView(browserViewMediateService(browserViewId));\n  });\n\n  function getWindowById(id: number): Electron.BrowserWindow {\n    for (let index = 0; index < windows.length; index++) {\n      const element = windows[index];\n      if (element.id === id) {\n        return element;\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/clipboard.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"clipboard-readText\", (type) => {\n        const text = electron_1.clipboard.readText(type);\n        electronSocket.emit(\"clipboard-readText-completed\", text);\n    });\n    socket.on(\"clipboard-writeText\", (text, type) => {\n        electron_1.clipboard.writeText(text, type);\n    });\n    socket.on(\"clipboard-readHTML\", (type) => {\n        const content = electron_1.clipboard.readHTML(type);\n        electronSocket.emit(\"clipboard-readHTML-completed\", content);\n    });\n    socket.on(\"clipboard-writeHTML\", (markup, type) => {\n        electron_1.clipboard.writeHTML(markup, type);\n    });\n    socket.on(\"clipboard-readRTF\", (type) => {\n        const content = electron_1.clipboard.readRTF(type);\n        electronSocket.emit(\"clipboard-readRTF-completed\", content);\n    });\n    socket.on(\"clipboard-writeRTF\", (text, type) => {\n        electron_1.clipboard.writeHTML(text, type);\n    });\n    socket.on(\"clipboard-readBookmark\", () => {\n        const bookmark = electron_1.clipboard.readBookmark();\n        electronSocket.emit(\"clipboard-readBookmark-completed\", bookmark);\n    });\n    socket.on(\"clipboard-writeBookmark\", (title, url, type) => {\n        electron_1.clipboard.writeBookmark(title, url, type);\n    });\n    socket.on(\"clipboard-readFindText\", () => {\n        const content = electron_1.clipboard.readFindText();\n        electronSocket.emit(\"clipboard-readFindText-completed\", content);\n    });\n    socket.on(\"clipboard-writeFindText\", (text) => {\n        electron_1.clipboard.writeFindText(text);\n    });\n    socket.on(\"clipboard-clear\", (type) => {\n        electron_1.clipboard.clear(type);\n    });\n    socket.on(\"clipboard-availableFormats\", (type) => {\n        const formats = electron_1.clipboard.availableFormats(type);\n        electronSocket.emit(\"clipboard-availableFormats-completed\", formats);\n    });\n    socket.on(\"clipboard-write\", (data, type) => {\n        electron_1.clipboard.write(data, type);\n    });\n    socket.on(\"clipboard-readImage\", (type) => {\n        const image = electron_1.clipboard.readImage(type);\n        electronSocket.emit(\"clipboard-readImage-completed\", {\n            1: image.toPNG().toString(\"base64\"),\n        });\n    });\n    socket.on(\"clipboard-writeImage\", (data, type) => {\n        const dataContent = JSON.parse(data);\n        const image = electron_1.nativeImage.createEmpty();\n        // tslint:disable-next-line: forin\n        for (const key in dataContent) {\n            const scaleFactor = key;\n            const bytes = data[key];\n            const buffer = Buffer.from(bytes, \"base64\");\n            image.addRepresentation({ scaleFactor: +scaleFactor, buffer: buffer });\n        }\n        electron_1.clipboard.writeImage(image, type);\n    });\n};\n//# sourceMappingURL=clipboard.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/clipboard.ts",
    "content": "import type { Socket } from \"net\";\nimport { clipboard, nativeImage } from \"electron\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n  socket.on(\"clipboard-readText\", (type) => {\n    const text = clipboard.readText(type);\n    electronSocket.emit(\"clipboard-readText-completed\", text);\n  });\n\n  socket.on(\"clipboard-writeText\", (text, type) => {\n    clipboard.writeText(text, type);\n  });\n\n  socket.on(\"clipboard-readHTML\", (type) => {\n    const content = clipboard.readHTML(type);\n    electronSocket.emit(\"clipboard-readHTML-completed\", content);\n  });\n\n  socket.on(\"clipboard-writeHTML\", (markup, type) => {\n    clipboard.writeHTML(markup, type);\n  });\n\n  socket.on(\"clipboard-readRTF\", (type) => {\n    const content = clipboard.readRTF(type);\n    electronSocket.emit(\"clipboard-readRTF-completed\", content);\n  });\n\n  socket.on(\"clipboard-writeRTF\", (text, type) => {\n    clipboard.writeHTML(text, type);\n  });\n\n  socket.on(\"clipboard-readBookmark\", () => {\n    const bookmark = clipboard.readBookmark();\n    electronSocket.emit(\"clipboard-readBookmark-completed\", bookmark);\n  });\n\n  socket.on(\"clipboard-writeBookmark\", (title, url, type) => {\n    clipboard.writeBookmark(title, url, type);\n  });\n\n  socket.on(\"clipboard-readFindText\", () => {\n    const content = clipboard.readFindText();\n    electronSocket.emit(\"clipboard-readFindText-completed\", content);\n  });\n\n  socket.on(\"clipboard-writeFindText\", (text) => {\n    clipboard.writeFindText(text);\n  });\n\n  socket.on(\"clipboard-clear\", (type) => {\n    clipboard.clear(type);\n  });\n\n  socket.on(\"clipboard-availableFormats\", (type) => {\n    const formats = clipboard.availableFormats(type);\n    electronSocket.emit(\"clipboard-availableFormats-completed\", formats);\n  });\n\n  socket.on(\"clipboard-write\", (data, type) => {\n    clipboard.write(data, type);\n  });\n\n  socket.on(\"clipboard-readImage\", (type) => {\n    const image = clipboard.readImage(type);\n    electronSocket.emit(\"clipboard-readImage-completed\", {\n      1: image.toPNG().toString(\"base64\"),\n    });\n  });\n\n  socket.on(\"clipboard-writeImage\", (data, type) => {\n    const dataContent = JSON.parse(data);\n    const image = nativeImage.createEmpty();\n\n    // tslint:disable-next-line: forin\n    for (const key in dataContent) {\n      const scaleFactor = key;\n      const bytes = data[key];\n      const buffer = Buffer.from(bytes, \"base64\");\n      image.addRepresentation({ scaleFactor: +scaleFactor, buffer: buffer });\n    }\n\n    clipboard.writeImage(image, type);\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/commandLine.js",
    "content": "\"use strict\";\nlet electronSocket;\nmodule.exports = (socket, app) => {\n    electronSocket = socket;\n    socket.on(\"appCommandLineAppendSwitch\", (the_switch, value) => {\n        app.commandLine.appendSwitch(the_switch, value);\n    });\n    socket.on(\"appCommandLineAppendArgument\", (value) => {\n        app.commandLine.appendArgument(value);\n    });\n    socket.on(\"appCommandLineHasSwitch\", (value) => {\n        const hasSwitch = app.commandLine.hasSwitch(value);\n        electronSocket.emit(\"appCommandLineHasSwitchCompleted\", hasSwitch);\n    });\n    socket.on(\"appCommandLineGetSwitchValue\", (the_switch) => {\n        const value = app.commandLine.getSwitchValue(the_switch);\n        electronSocket.emit(\"appCommandLineGetSwitchValueCompleted\", value);\n    });\n};\n//# sourceMappingURL=commandLine.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/commandLine.ts",
    "content": "import type { Socket } from \"net\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket, app: Electron.App) => {\n  electronSocket = socket;\n\n  socket.on(\n    \"appCommandLineAppendSwitch\",\n    (the_switch: string, value: string) => {\n      app.commandLine.appendSwitch(the_switch, value);\n    },\n  );\n\n  socket.on(\"appCommandLineAppendArgument\", (value: string) => {\n    app.commandLine.appendArgument(value);\n  });\n\n  socket.on(\"appCommandLineHasSwitch\", (value: string) => {\n    const hasSwitch = app.commandLine.hasSwitch(value);\n    electronSocket.emit(\"appCommandLineHasSwitchCompleted\", hasSwitch);\n  });\n\n  socket.on(\"appCommandLineGetSwitchValue\", (the_switch: string) => {\n    const value = app.commandLine.getSwitchValue(the_switch);\n    electronSocket.emit(\"appCommandLineGetSwitchValueCompleted\", value);\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/dialog.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"showMessageBox\", async (browserWindow, options, guid) => {\n        if (\"id\" in browserWindow) {\n            const window = electron_1.BrowserWindow.fromId(browserWindow.id);\n            const messageBoxReturnValue = await electron_1.dialog.showMessageBox(window, options);\n            electronSocket.emit(\"showMessageBoxComplete\" + guid, [\n                messageBoxReturnValue.response,\n                messageBoxReturnValue.checkboxChecked,\n            ]);\n        }\n        else {\n            const id = guid || options;\n            const messageBoxReturnValue = await electron_1.dialog.showMessageBox(browserWindow);\n            electronSocket.emit(\"showMessageBoxComplete\" + id, [\n                messageBoxReturnValue.response,\n                messageBoxReturnValue.checkboxChecked,\n            ]);\n        }\n    });\n    socket.on(\"showOpenDialog\", async (browserWindow, options, guid) => {\n        const window = electron_1.BrowserWindow.fromId(browserWindow.id);\n        const openDialogReturnValue = await electron_1.dialog.showOpenDialog(window, options);\n        electronSocket.emit(\"showOpenDialogComplete\" + guid, openDialogReturnValue.filePaths || []);\n    });\n    socket.on(\"showSaveDialog\", async (browserWindow, options, guid) => {\n        const window = electron_1.BrowserWindow.fromId(browserWindow.id);\n        const saveDialogReturnValue = await electron_1.dialog.showSaveDialog(window, options);\n        electronSocket.emit(\"showSaveDialogComplete\" + guid, saveDialogReturnValue.filePath || \"\");\n    });\n    socket.on(\"showErrorBox\", (title, content) => {\n        electron_1.dialog.showErrorBox(title, content);\n    });\n    socket.on(\"showCertificateTrustDialog\", async (browserWindow, options, guid) => {\n        const window = electron_1.BrowserWindow.fromId(browserWindow.id);\n        await electron_1.dialog.showCertificateTrustDialog(window, options);\n        electronSocket.emit(\"showCertificateTrustDialogComplete\" + guid);\n    });\n};\n//# sourceMappingURL=dialog.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/dialog.ts",
    "content": "import type { Socket } from \"net\";\nimport { BrowserWindow, dialog } from \"electron\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n  socket.on(\"showMessageBox\", async (browserWindow, options, guid) => {\n    if (\"id\" in browserWindow) {\n      const window = BrowserWindow.fromId(browserWindow.id);\n\n      const messageBoxReturnValue = await dialog.showMessageBox(\n        window,\n        options,\n      );\n      electronSocket.emit(\"showMessageBoxComplete\" + guid, [\n        messageBoxReturnValue.response,\n        messageBoxReturnValue.checkboxChecked,\n      ]);\n    } else {\n      const id = guid || options;\n      const messageBoxReturnValue = await dialog.showMessageBox(browserWindow);\n\n      electronSocket.emit(\"showMessageBoxComplete\" + id, [\n        messageBoxReturnValue.response,\n        messageBoxReturnValue.checkboxChecked,\n      ]);\n    }\n  });\n\n  socket.on(\"showOpenDialog\", async (browserWindow, options, guid) => {\n    const window = BrowserWindow.fromId(browserWindow.id);\n    const openDialogReturnValue = await dialog.showOpenDialog(window, options);\n\n    electronSocket.emit(\n      \"showOpenDialogComplete\" + guid,\n      openDialogReturnValue.filePaths || [],\n    );\n  });\n\n  socket.on(\"showSaveDialog\", async (browserWindow, options, guid) => {\n    const window = BrowserWindow.fromId(browserWindow.id);\n    const saveDialogReturnValue = await dialog.showSaveDialog(window, options);\n\n    electronSocket.emit(\n      \"showSaveDialogComplete\" + guid,\n      saveDialogReturnValue.filePath || \"\",\n    );\n  });\n\n  socket.on(\"showErrorBox\", (title, content) => {\n    dialog.showErrorBox(title, content);\n  });\n\n  socket.on(\n    \"showCertificateTrustDialog\",\n    async (browserWindow, options, guid) => {\n      const window = BrowserWindow.fromId(browserWindow.id);\n      await dialog.showCertificateTrustDialog(window, options);\n\n      electronSocket.emit(\"showCertificateTrustDialogComplete\" + guid);\n    },\n  );\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/dock.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"dock-bounce\", (type) => {\n        const id = electron_1.app.dock.bounce(type);\n        electronSocket.emit(\"dock-bounce-completed\", id);\n    });\n    socket.on(\"dock-cancelBounce\", (id) => {\n        electron_1.app.dock.cancelBounce(id);\n    });\n    socket.on(\"dock-downloadFinished\", (filePath) => {\n        electron_1.app.dock.downloadFinished(filePath);\n    });\n    socket.on(\"dock-setBadge\", (text) => {\n        electron_1.app.dock.setBadge(text);\n    });\n    socket.on(\"dock-getBadge\", () => {\n        const text = electron_1.app.dock.getBadge();\n        electronSocket.emit(\"dock-getBadge-completed\", text);\n    });\n    socket.on(\"dock-hide\", () => {\n        electron_1.app.dock.hide();\n    });\n    socket.on(\"dock-show\", () => {\n        electron_1.app.dock.show();\n    });\n    socket.on(\"dock-isVisible\", () => {\n        const isVisible = electron_1.app.dock.isVisible();\n        electronSocket.emit(\"dock-isVisible-completed\", isVisible);\n    });\n    socket.on(\"dock-setMenu\", (menuItems) => {\n        let menu = null;\n        if (menuItems) {\n            menu = electron_1.Menu.buildFromTemplate(menuItems);\n            addMenuItemClickConnector(menu.items, (id) => {\n                electronSocket.emit(\"dockMenuItemClicked\", id);\n            });\n        }\n        electron_1.app.dock.setMenu(menu);\n    });\n    // TODO: Menu (macOS) still to be implemented\n    socket.on(\"dock-getMenu\", () => {\n        const menu = electron_1.app.dock.getMenu();\n        electronSocket.emit(\"dock-getMenu-completed\", menu);\n    });\n    socket.on(\"dock-setIcon\", (image) => {\n        electron_1.app.dock.setIcon(image);\n    });\n    function addMenuItemClickConnector(menuItems, callback) {\n        menuItems.forEach((item) => {\n            if (item.submenu && item.submenu.items.length > 0) {\n                addMenuItemClickConnector(item.submenu.items, callback);\n            }\n            if (\"id\" in item && item.id) {\n                item.click = () => {\n                    callback(item.id);\n                };\n            }\n        });\n    }\n};\n//# sourceMappingURL=dock.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/dock.ts",
    "content": "import type { Socket } from \"net\";\nimport { app, Menu } from \"electron\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n\n  socket.on(\"dock-bounce\", (type) => {\n    const id = app.dock.bounce(type);\n    electronSocket.emit(\"dock-bounce-completed\", id);\n  });\n\n  socket.on(\"dock-cancelBounce\", (id) => {\n    app.dock.cancelBounce(id);\n  });\n\n  socket.on(\"dock-downloadFinished\", (filePath) => {\n    app.dock.downloadFinished(filePath);\n  });\n\n  socket.on(\"dock-setBadge\", (text) => {\n    app.dock.setBadge(text);\n  });\n\n  socket.on(\"dock-getBadge\", () => {\n    const text = app.dock.getBadge();\n    electronSocket.emit(\"dock-getBadge-completed\", text);\n  });\n\n  socket.on(\"dock-hide\", () => {\n    app.dock.hide();\n  });\n\n  socket.on(\"dock-show\", () => {\n    app.dock.show();\n  });\n\n  socket.on(\"dock-isVisible\", () => {\n    const isVisible = app.dock.isVisible();\n    electronSocket.emit(\"dock-isVisible-completed\", isVisible);\n  });\n\n  socket.on(\"dock-setMenu\", (menuItems) => {\n    let menu = null;\n\n    if (menuItems) {\n      menu = Menu.buildFromTemplate(menuItems);\n\n      addMenuItemClickConnector(menu.items, (id) => {\n        electronSocket.emit(\"dockMenuItemClicked\", id);\n      });\n    }\n\n    app.dock.setMenu(menu);\n  });\n\n  // TODO: Menu (macOS) still to be implemented\n  socket.on(\"dock-getMenu\", () => {\n    const menu = app.dock.getMenu();\n    electronSocket.emit(\"dock-getMenu-completed\", menu);\n  });\n\n  socket.on(\"dock-setIcon\", (image) => {\n    app.dock.setIcon(image);\n  });\n\n  function addMenuItemClickConnector(menuItems, callback) {\n    menuItems.forEach((item) => {\n      if (item.submenu && item.submenu.items.length > 0) {\n        addMenuItemClickConnector(item.submenu.items, callback);\n      }\n\n      if (\"id\" in item && item.id) {\n        item.click = () => {\n          callback(item.id);\n        };\n      }\n    });\n  }\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/globalShortcut.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"globalShortcut-register\", (accelerator) => {\n        electron_1.globalShortcut.register(accelerator, () => {\n            electronSocket.emit(\"globalShortcut-pressed\", accelerator);\n        });\n    });\n    socket.on(\"globalShortcut-isRegistered\", (accelerator) => {\n        const isRegistered = electron_1.globalShortcut.isRegistered(accelerator);\n        electronSocket.emit(\"globalShortcut-isRegisteredCompleted\", isRegistered);\n    });\n    socket.on(\"globalShortcut-unregister\", (accelerator) => {\n        electron_1.globalShortcut.unregister(accelerator);\n    });\n    socket.on(\"globalShortcut-unregisterAll\", () => {\n        try {\n            electron_1.globalShortcut.unregisterAll();\n        }\n        catch (error) { }\n    });\n};\n//# sourceMappingURL=globalShortcut.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/globalShortcut.ts",
    "content": "import type { Socket } from \"net\";\nimport { globalShortcut } from \"electron\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n  socket.on(\"globalShortcut-register\", (accelerator) => {\n    globalShortcut.register(accelerator, () => {\n      electronSocket.emit(\"globalShortcut-pressed\", accelerator);\n    });\n  });\n\n  socket.on(\"globalShortcut-isRegistered\", (accelerator) => {\n    const isRegistered = globalShortcut.isRegistered(accelerator);\n\n    electronSocket.emit(\"globalShortcut-isRegisteredCompleted\", isRegistered);\n  });\n\n  socket.on(\"globalShortcut-unregister\", (accelerator) => {\n    globalShortcut.unregister(accelerator);\n  });\n\n  socket.on(\"globalShortcut-unregisterAll\", () => {\n    try {\n      globalShortcut.unregisterAll();\n    } catch (error) {}\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/ipc.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"registerIpcMainChannel\", (channel) => {\n        electron_1.ipcMain.on(channel, (event, args) => {\n            electronSocket.emit(channel, [event.preventDefault(), args]);\n        });\n    });\n    socket.on(\"registerSyncIpcMainChannel\", (channel) => {\n        electron_1.ipcMain.on(channel, (event, args) => {\n            const x = socket;\n            x.removeAllListeners(channel + \"Sync\");\n            socket.on(channel + \"Sync\", (result) => {\n                event.returnValue = result;\n            });\n            electronSocket.emit(channel, [event.preventDefault(), args]);\n        });\n    });\n    socket.on(\"registerOnceIpcMainChannel\", (channel) => {\n        electron_1.ipcMain.once(channel, (event, args) => {\n            electronSocket.emit(channel, [event.preventDefault(), args]);\n        });\n    });\n    socket.on(\"removeAllListenersIpcMainChannel\", (channel) => {\n        electron_1.ipcMain.removeAllListeners(channel);\n    });\n    socket.on(\"sendToIpcRenderer\", (browserWindow, channel, data) => {\n        const window = electron_1.BrowserWindow.fromId(browserWindow.id);\n        if (window) {\n            window.webContents.send(channel, ...data);\n        }\n    });\n    socket.on(\"sendToIpcRendererBrowserView\", (id, channel, data) => {\n        const browserViews = (global[\"browserViews\"] =\n            global[\"browserViews\"] || []);\n        let view = null;\n        for (let i = 0; i < browserViews.length; i++) {\n            if (browserViews[i][\"id\"] === id) {\n                view = browserViews[i];\n                break;\n            }\n        }\n        if (view) {\n            view.webContents.send(channel, ...data);\n        }\n    });\n    socket.on(\"registerHandleIpcMainChannel\", (channel) => {\n        electron_1.ipcMain.handle(channel, (event, args) => {\n            return new Promise((resolve, _reject) => {\n                socket.removeAllListeners(channel + \"Handle\");\n                socket.on(channel + \"Handle\", (result) => {\n                    resolve(result);\n                });\n                electronSocket.emit(channel, [event.preventDefault(), args]);\n            });\n        });\n    });\n    socket.on(\"registerHandleOnceIpcMainChannel\", (channel) => {\n        electron_1.ipcMain.handleOnce(channel, (event, args) => {\n            return new Promise((resolve, _reject) => {\n                socket.removeAllListeners(channel + \"HandleOnce\");\n                socket.once(channel + \"HandleOnce\", (result) => {\n                    resolve(result);\n                });\n                electronSocket.emit(channel, [event.preventDefault(), args]);\n            });\n        });\n    });\n    socket.on(\"removeHandlerIpcMainChannel\", (channel) => {\n        electron_1.ipcMain.removeHandler(channel);\n    });\n    // Integration helpers: programmatically click menu items from renderer tests\n    electron_1.ipcMain.on(\"integration-click-application-menu\", (event, id) => {\n        try {\n            const menu = electron_1.Menu.getApplicationMenu();\n            const mi = menu ? menu.getMenuItemById(id) : null;\n            if (mi && typeof mi.click === \"function\") {\n                const bw = electron_1.BrowserWindow.fromWebContents(event.sender);\n                mi.click(undefined, bw, undefined);\n            }\n        }\n        catch {\n            /* ignore */\n        }\n    });\n    electron_1.ipcMain.on(\"integration-click-context-menu\", (event, windowId, id) => {\n        try {\n            const entries = global[\"contextMenuItems\"] || [];\n            const entry = entries.find((x) => x.browserWindowId === windowId);\n            const mi = entry?.menu?.items?.find((i) => i.id === id);\n            if (mi && typeof mi.click === \"function\") {\n                const bw = electron_1.BrowserWindow.fromId(windowId);\n                mi.click(undefined, bw, undefined);\n            }\n        }\n        catch {\n            /* ignore */\n        }\n    });\n};\n//# sourceMappingURL=ipc.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/ipc.ts",
    "content": "import type { Socket } from \"net\";\nimport { ipcMain, BrowserWindow, BrowserView, Menu } from \"electron\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n  socket.on(\"registerIpcMainChannel\", (channel) => {\n    ipcMain.on(channel, (event, args) => {\n      electronSocket.emit(channel, [event.preventDefault(), args]);\n    });\n  });\n\n  socket.on(\"registerSyncIpcMainChannel\", (channel) => {\n    ipcMain.on(channel, (event, args) => {\n      const x = <any>socket;\n      x.removeAllListeners(channel + \"Sync\");\n      socket.on(channel + \"Sync\", (result) => {\n        event.returnValue = result;\n      });\n\n      electronSocket.emit(channel, [event.preventDefault(), args]);\n    });\n  });\n\n  socket.on(\"registerOnceIpcMainChannel\", (channel) => {\n    ipcMain.once(channel, (event, args) => {\n      electronSocket.emit(channel, [event.preventDefault(), args]);\n    });\n  });\n\n  socket.on(\"removeAllListenersIpcMainChannel\", (channel) => {\n    ipcMain.removeAllListeners(channel);\n  });\n\n  socket.on(\"sendToIpcRenderer\", (browserWindow, channel, data) => {\n    const window = BrowserWindow.fromId(browserWindow.id);\n\n    if (window) {\n      window.webContents.send(channel, ...data);\n    }\n  });\n\n  socket.on(\"sendToIpcRendererBrowserView\", (id, channel, data) => {\n    const browserViews: BrowserView[] = (global[\"browserViews\"] =\n      global[\"browserViews\"] || []) as BrowserView[];\n    let view: BrowserView = null;\n    for (let i = 0; i < browserViews.length; i++) {\n      if (browserViews[i][\"id\"] === id) {\n        view = browserViews[i];\n        break;\n      }\n    }\n\n    if (view) {\n      view.webContents.send(channel, ...data);\n    }\n  });\n\n  socket.on(\"registerHandleIpcMainChannel\", (channel) => {\n    ipcMain.handle(channel, (event, args) => {\n      return new Promise((resolve, _reject) => {\n        socket.removeAllListeners(channel + \"Handle\");\n        socket.on(channel + \"Handle\", (result) => {\n          resolve(result);\n        });\n        electronSocket.emit(channel, [event.preventDefault(), args]);\n      });\n    });\n  });\n\n  socket.on(\"registerHandleOnceIpcMainChannel\", (channel) => {\n    ipcMain.handleOnce(channel, (event, args) => {\n      return new Promise((resolve, _reject) => {\n        socket.removeAllListeners(channel + \"HandleOnce\");\n        socket.once(channel + \"HandleOnce\", (result) => {\n          resolve(result);\n        });\n        electronSocket.emit(channel, [event.preventDefault(), args]);\n      });\n    });\n  });\n\n  socket.on(\"removeHandlerIpcMainChannel\", (channel) => {\n    ipcMain.removeHandler(channel);\n  });\n\n  // Integration helpers: programmatically click menu items from renderer tests\n  ipcMain.on(\"integration-click-application-menu\", (event, id: string) => {\n    try {\n      const menu = Menu.getApplicationMenu();\n      const mi = menu ? menu.getMenuItemById(id) : null;\n      if (mi && typeof (mi as any).click === \"function\") {\n        const bw = BrowserWindow.fromWebContents(event.sender);\n        (mi as any).click(undefined, bw, undefined);\n      }\n    } catch {\n      /* ignore */\n    }\n  });\n\n  ipcMain.on(\n    \"integration-click-context-menu\",\n    (event, windowId: number, id: string) => {\n      try {\n        const entries = (global as any)[\"contextMenuItems\"] || [];\n        const entry = entries.find((x: any) => x.browserWindowId === windowId);\n        const mi = entry?.menu?.items?.find((i: any) => i.id === id);\n        if (mi && typeof (mi as any).click === \"function\") {\n          const bw = BrowserWindow.fromId(windowId);\n          (mi as any).click(undefined, bw, undefined);\n        }\n      } catch {\n        /* ignore */\n      }\n    },\n  );\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/menu.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nconst contextMenuItems = (global[\"contextMenuItems\"] =\n    global[\"contextMenuItems\"] || []);\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"menu-setContextMenu\", (browserWindowId, menuItems) => {\n        const menu = electron_1.Menu.buildFromTemplate(menuItems);\n        addContextMenuItemClickConnector(menu.items, browserWindowId, (id, windowId) => {\n            electronSocket.emit(\"contextMenuItemClicked\", [id, windowId]);\n        });\n        const index = contextMenuItems.findIndex((contextMenu) => contextMenu.browserWindowId === browserWindowId);\n        const contextMenuItem = {\n            menu: menu,\n            browserWindowId: browserWindowId,\n        };\n        if (index === -1) {\n            contextMenuItems.push(contextMenuItem);\n        }\n        else {\n            contextMenuItems[index] = contextMenuItem;\n        }\n    });\n    function addContextMenuItemClickConnector(menuItems, browserWindowId, callback) {\n        menuItems.forEach((item) => {\n            if (item.submenu && item.submenu.items.length > 0) {\n                addContextMenuItemClickConnector(item.submenu.items, browserWindowId, callback);\n            }\n            if (\"id\" in item && item.id) {\n                item.click = () => {\n                    callback(item.id, browserWindowId);\n                };\n            }\n        });\n    }\n    socket.on(\"menu-contextMenuPopup\", (browserWindowId) => {\n        contextMenuItems.forEach((x) => {\n            if (x.browserWindowId === browserWindowId) {\n                const browserWindow = electron_1.BrowserWindow.fromId(browserWindowId);\n                x.menu.popup(browserWindow);\n            }\n        });\n    });\n    socket.on(\"menu-setApplicationMenu\", (menuItems) => {\n        const menu = electron_1.Menu.buildFromTemplate(menuItems);\n        addMenuItemClickConnector(menu.items, (id) => {\n            electronSocket.emit(\"menuItemClicked\", id);\n        });\n        electron_1.Menu.setApplicationMenu(menu);\n    });\n    function addMenuItemClickConnector(menuItems, callback) {\n        menuItems.forEach((item) => {\n            if (item.submenu && item.submenu.items.length > 0) {\n                addMenuItemClickConnector(item.submenu.items, callback);\n            }\n            if (\"id\" in item && item.id) {\n                item.click = () => {\n                    callback(item.id);\n                };\n            }\n        });\n    }\n};\n//# sourceMappingURL=menu.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/menu.ts",
    "content": "import type { Socket } from \"net\";\nimport { Menu, BrowserWindow } from \"electron\";\n\nconst contextMenuItems = (global[\"contextMenuItems\"] =\n  global[\"contextMenuItems\"] || []);\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n  socket.on(\"menu-setContextMenu\", (browserWindowId, menuItems) => {\n    const menu = Menu.buildFromTemplate(menuItems);\n\n    addContextMenuItemClickConnector(\n      menu.items,\n      browserWindowId,\n      (id, windowId) => {\n        electronSocket.emit(\"contextMenuItemClicked\", [id, windowId]);\n      },\n    );\n\n    const index = contextMenuItems.findIndex(\n      (contextMenu) => contextMenu.browserWindowId === browserWindowId,\n    );\n\n    const contextMenuItem = {\n      menu: menu,\n      browserWindowId: browserWindowId,\n    };\n\n    if (index === -1) {\n      contextMenuItems.push(contextMenuItem);\n    } else {\n      contextMenuItems[index] = contextMenuItem;\n    }\n  });\n\n  function addContextMenuItemClickConnector(\n    menuItems,\n    browserWindowId,\n    callback,\n  ) {\n    menuItems.forEach((item) => {\n      if (item.submenu && item.submenu.items.length > 0) {\n        addContextMenuItemClickConnector(\n          item.submenu.items,\n          browserWindowId,\n          callback,\n        );\n      }\n\n      if (\"id\" in item && item.id) {\n        item.click = () => {\n          callback(item.id, browserWindowId);\n        };\n      }\n    });\n  }\n\n  socket.on(\"menu-contextMenuPopup\", (browserWindowId) => {\n    contextMenuItems.forEach((x) => {\n      if (x.browserWindowId === browserWindowId) {\n        const browserWindow = BrowserWindow.fromId(browserWindowId);\n        x.menu.popup(browserWindow);\n      }\n    });\n  });\n\n  socket.on(\"menu-setApplicationMenu\", (menuItems) => {\n    const menu = Menu.buildFromTemplate(menuItems);\n\n    addMenuItemClickConnector(menu.items, (id) => {\n      electronSocket.emit(\"menuItemClicked\", id);\n    });\n\n    Menu.setApplicationMenu(menu);\n  });\n\n  function addMenuItemClickConnector(menuItems, callback) {\n    menuItems.forEach((item) => {\n      if (item.submenu && item.submenu.items.length > 0) {\n        addMenuItemClickConnector(item.submenu.items, callback);\n      }\n\n      if (\"id\" in item && item.id) {\n        item.click = () => {\n          callback(item.id);\n        };\n      }\n    });\n  }\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/nativeTheme.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"nativeTheme-shouldUseDarkColors\", () => {\n        const shouldUseDarkColors = electron_1.nativeTheme.shouldUseDarkColors;\n        electronSocket.emit(\"nativeTheme-shouldUseDarkColors-completed\", shouldUseDarkColors);\n    });\n    socket.on(\"nativeTheme-shouldUseHighContrastColors\", () => {\n        const shouldUseHighContrastColors = electron_1.nativeTheme.shouldUseHighContrastColors;\n        electronSocket.emit(\"nativeTheme-shouldUseHighContrastColors-completed\", shouldUseHighContrastColors);\n    });\n    socket.on(\"nativeTheme-shouldUseInvertedColorScheme\", () => {\n        const shouldUseInvertedColorScheme = electron_1.nativeTheme.shouldUseInvertedColorScheme;\n        electronSocket.emit(\"nativeTheme-shouldUseInvertedColorScheme-completed\", shouldUseInvertedColorScheme);\n    });\n    socket.on(\"nativeTheme-getThemeSource\", () => {\n        const themeSource = electron_1.nativeTheme.themeSource;\n        electronSocket.emit(\"nativeTheme-getThemeSource-completed\", themeSource);\n    });\n    socket.on(\"nativeTheme-themeSource\", (themeSource) => {\n        electron_1.nativeTheme.themeSource = themeSource;\n    });\n    socket.on(\"register-nativeTheme-updated\", (id) => {\n        electron_1.nativeTheme.on(\"updated\", () => {\n            electronSocket.emit(\"nativeTheme-updated\" + id);\n        });\n    });\n};\n//# sourceMappingURL=nativeTheme.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/nativeTheme.ts",
    "content": "import type { Socket } from \"net\";\nimport { nativeTheme } from \"electron\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n\n  socket.on(\"nativeTheme-shouldUseDarkColors\", () => {\n    const shouldUseDarkColors = nativeTheme.shouldUseDarkColors;\n\n    electronSocket.emit(\n      \"nativeTheme-shouldUseDarkColors-completed\",\n      shouldUseDarkColors,\n    );\n  });\n\n  socket.on(\"nativeTheme-shouldUseHighContrastColors\", () => {\n    const shouldUseHighContrastColors = nativeTheme.shouldUseHighContrastColors;\n\n    electronSocket.emit(\n      \"nativeTheme-shouldUseHighContrastColors-completed\",\n      shouldUseHighContrastColors,\n    );\n  });\n\n  socket.on(\"nativeTheme-shouldUseInvertedColorScheme\", () => {\n    const shouldUseInvertedColorScheme =\n      nativeTheme.shouldUseInvertedColorScheme;\n\n    electronSocket.emit(\n      \"nativeTheme-shouldUseInvertedColorScheme-completed\",\n      shouldUseInvertedColorScheme,\n    );\n  });\n\n  socket.on(\"nativeTheme-getThemeSource\", () => {\n    const themeSource = nativeTheme.themeSource;\n\n    electronSocket.emit(\"nativeTheme-getThemeSource-completed\", themeSource);\n  });\n\n  socket.on(\"nativeTheme-themeSource\", (themeSource) => {\n    nativeTheme.themeSource = themeSource;\n  });\n\n  socket.on(\"register-nativeTheme-updated\", (id) => {\n    nativeTheme.on(\"updated\", () => {\n      electronSocket.emit(\"nativeTheme-updated\" + id);\n    });\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/notification.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nconst notifications = (global[\"notifications\"] =\n    global[\"notifications\"] || []);\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"createNotification\", (options) => {\n        const notification = new electron_1.Notification(options);\n        let haveEvent = false;\n        if (options.showID) {\n            haveEvent = true;\n            notification.on(\"show\", () => {\n                electronSocket.emit(\"NotificationEventShow\", options.showID);\n            });\n        }\n        if (options.clickID) {\n            haveEvent = true;\n            notification.on(\"click\", () => {\n                electronSocket.emit(\"NotificationEventClick\", options.clickID);\n            });\n        }\n        if (options.closeID) {\n            haveEvent = true;\n            notification.on(\"close\", () => {\n                electronSocket.emit(\"NotificationEventClose\", options.closeID);\n            });\n        }\n        if (options.replyID) {\n            haveEvent = true;\n            notification.on(\"reply\", (event, value) => {\n                electronSocket.emit(\"NotificationEventReply\", [options.replyID, value]);\n            });\n        }\n        if (options.actionID) {\n            haveEvent = true;\n            notification.on(\"action\", (event, value) => {\n                electronSocket.emit(\"NotificationEventAction\", [\n                    options.actionID,\n                    value,\n                ]);\n            });\n        }\n        if (haveEvent) {\n            notifications.push(notification);\n        }\n        notification.show();\n    });\n    socket.on(\"notificationIsSupported\", () => {\n        const isSupported = electron_1.Notification.isSupported();\n        electronSocket.emit(\"notificationIsSupportedCompleted\", isSupported);\n    });\n};\n//# sourceMappingURL=notification.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/notification.ts",
    "content": "import type { Socket } from \"net\";\nimport { Notification } from \"electron\";\n\nconst notifications: Electron.Notification[] = (global[\"notifications\"] =\n  global[\"notifications\"] || []) as Electron.Notification[];\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n  socket.on(\"createNotification\", (options) => {\n    const notification = new Notification(options);\n    let haveEvent = false;\n\n    if (options.showID) {\n      haveEvent = true;\n      notification.on(\"show\", () => {\n        electronSocket.emit(\"NotificationEventShow\", options.showID);\n      });\n    }\n\n    if (options.clickID) {\n      haveEvent = true;\n      notification.on(\"click\", () => {\n        electronSocket.emit(\"NotificationEventClick\", options.clickID);\n      });\n    }\n\n    if (options.closeID) {\n      haveEvent = true;\n      notification.on(\"close\", () => {\n        electronSocket.emit(\"NotificationEventClose\", options.closeID);\n      });\n    }\n\n    if (options.replyID) {\n      haveEvent = true;\n      notification.on(\"reply\", (event, value) => {\n        electronSocket.emit(\"NotificationEventReply\", [options.replyID, value]);\n      });\n    }\n\n    if (options.actionID) {\n      haveEvent = true;\n      notification.on(\"action\", (event, value) => {\n        electronSocket.emit(\"NotificationEventAction\", [\n          options.actionID,\n          value,\n        ]);\n      });\n    }\n\n    if (haveEvent) {\n      notifications.push(notification);\n    }\n\n    notification.show();\n  });\n\n  socket.on(\"notificationIsSupported\", () => {\n    const isSupported = Notification.isSupported();\n    electronSocket.emit(\"notificationIsSupportedCompleted\", isSupported);\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/powerMonitor.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"register-powerMonitor-lock-screen\", () => {\n        electron_1.powerMonitor.on(\"lock-screen\", () => {\n            electronSocket.emit(\"powerMonitor-lock-screen\");\n        });\n    });\n    socket.on(\"register-powerMonitor-unlock-screen\", () => {\n        electron_1.powerMonitor.on(\"unlock-screen\", () => {\n            electronSocket.emit(\"powerMonitor-unlock-screen\");\n        });\n    });\n    socket.on(\"register-powerMonitor-suspend\", () => {\n        electron_1.powerMonitor.on(\"suspend\", () => {\n            electronSocket.emit(\"powerMonitor-suspend\");\n        });\n    });\n    socket.on(\"register-powerMonitor-resume\", () => {\n        electron_1.powerMonitor.on(\"resume\", () => {\n            electronSocket.emit(\"powerMonitor-resume\");\n        });\n    });\n    socket.on(\"register-powerMonitor-ac\", () => {\n        electron_1.powerMonitor.on(\"on-ac\", () => {\n            electronSocket.emit(\"powerMonitor-ac\");\n        });\n    });\n    socket.on(\"register-powerMonitor-battery\", () => {\n        electron_1.powerMonitor.on(\"on-battery\", () => {\n            electronSocket.emit(\"powerMonitor-battery\");\n        });\n    });\n    socket.on(\"register-powerMonitor-shutdown\", () => {\n        electron_1.powerMonitor.on(\"shutdown\", () => {\n            electronSocket.emit(\"powerMonitor-shutdown\");\n        });\n    });\n};\n//# sourceMappingURL=powerMonitor.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/powerMonitor.ts",
    "content": "import type { Socket } from \"net\";\nimport { powerMonitor } from \"electron\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n  socket.on(\"register-powerMonitor-lock-screen\", () => {\n    powerMonitor.on(\"lock-screen\", () => {\n      electronSocket.emit(\"powerMonitor-lock-screen\");\n    });\n  });\n  socket.on(\"register-powerMonitor-unlock-screen\", () => {\n    powerMonitor.on(\"unlock-screen\", () => {\n      electronSocket.emit(\"powerMonitor-unlock-screen\");\n    });\n  });\n  socket.on(\"register-powerMonitor-suspend\", () => {\n    powerMonitor.on(\"suspend\", () => {\n      electronSocket.emit(\"powerMonitor-suspend\");\n    });\n  });\n  socket.on(\"register-powerMonitor-resume\", () => {\n    powerMonitor.on(\"resume\", () => {\n      electronSocket.emit(\"powerMonitor-resume\");\n    });\n  });\n  socket.on(\"register-powerMonitor-ac\", () => {\n    powerMonitor.on(\"on-ac\", () => {\n      electronSocket.emit(\"powerMonitor-ac\");\n    });\n  });\n  socket.on(\"register-powerMonitor-battery\", () => {\n    powerMonitor.on(\"on-battery\", () => {\n      electronSocket.emit(\"powerMonitor-battery\");\n    });\n  });\n  socket.on(\"register-powerMonitor-shutdown\", () => {\n    powerMonitor.on(\"shutdown\", () => {\n      electronSocket.emit(\"powerMonitor-shutdown\");\n    });\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/process.js",
    "content": "\"use strict\";\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"process-execPath\", () => {\n        const value = process.execPath;\n        electronSocket.emit(\"process-execPath-completed\", value);\n    });\n    socket.on(\"process-argv\", () => {\n        const value = process.argv;\n        electronSocket.emit(\"process-argv-completed\", value);\n    });\n    socket.on(\"process-type\", () => {\n        const value = process.type;\n        electronSocket.emit(\"process-type-completed\", value);\n    });\n    socket.on(\"process-versions\", () => {\n        const value = process.versions;\n        electronSocket.emit(\"process-versions-completed\", value);\n    });\n    socket.on(\"process-defaultApp\", () => {\n        if (process.defaultApp === undefined) {\n            electronSocket.emit(\"process-defaultApp-completed\", false);\n            return;\n        }\n        electronSocket.emit(\"process-defaultApp-completed\", process.defaultApp);\n    });\n    socket.on(\"process-isMainFrame\", () => {\n        if (process.isMainFrame === undefined) {\n            electronSocket.emit(\"process-isMainFrame-completed\", false);\n            return;\n        }\n        electronSocket.emit(\"process-isMainFrame-completed\", process.isMainFrame);\n    });\n    socket.on(\"process-resourcesPath\", () => {\n        const value = process.resourcesPath;\n        electronSocket.emit(\"process-resourcesPath-completed\", value);\n    });\n    socket.on(\"process-upTime\", () => {\n        let value = process.uptime();\n        if (value === undefined) {\n            value = -1;\n        }\n        electronSocket.emit(\"process-upTime-completed\", value);\n    });\n    socket.on(\"process-pid\", () => {\n        if (process.pid === undefined) {\n            electronSocket.emit(\"process-pid-completed\", -1);\n            return;\n        }\n        electronSocket.emit(\"process-pid-completed\", process.pid);\n    });\n    socket.on(\"process-arch\", () => {\n        const value = process.arch;\n        electronSocket.emit(\"process-arch-completed\", value);\n    });\n    socket.on(\"process-platform\", () => {\n        const value = process.platform;\n        electronSocket.emit(\"process-platform-completed\", value);\n    });\n};\n//# sourceMappingURL=process.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/process.ts",
    "content": "import type { Socket } from \"net\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n\n  socket.on(\"process-execPath\", () => {\n    const value = process.execPath;\n    electronSocket.emit(\"process-execPath-completed\", value);\n  });\n\n  socket.on(\"process-argv\", () => {\n    const value = process.argv;\n    electronSocket.emit(\"process-argv-completed\", value);\n  });\n\n  socket.on(\"process-type\", () => {\n    const value = process.type;\n    electronSocket.emit(\"process-type-completed\", value);\n  });\n\n  socket.on(\"process-versions\", () => {\n    const value = process.versions;\n    electronSocket.emit(\"process-versions-completed\", value);\n  });\n\n  socket.on(\"process-defaultApp\", () => {\n    if (process.defaultApp === undefined) {\n      electronSocket.emit(\"process-defaultApp-completed\", false);\n      return;\n    }\n    electronSocket.emit(\"process-defaultApp-completed\", process.defaultApp);\n  });\n\n  socket.on(\"process-isMainFrame\", () => {\n    if (process.isMainFrame === undefined) {\n      electronSocket.emit(\"process-isMainFrame-completed\", false);\n      return;\n    }\n    electronSocket.emit(\"process-isMainFrame-completed\", process.isMainFrame);\n  });\n\n  socket.on(\"process-resourcesPath\", () => {\n    const value = process.resourcesPath;\n    electronSocket.emit(\"process-resourcesPath-completed\", value);\n  });\n\n  socket.on(\"process-upTime\", () => {\n    let value = process.uptime();\n    if (value === undefined) {\n      value = -1;\n    }\n    electronSocket.emit(\"process-upTime-completed\", value);\n  });\n\n  socket.on(\"process-pid\", () => {\n    if (process.pid === undefined) {\n      electronSocket.emit(\"process-pid-completed\", -1);\n      return;\n    }\n    electronSocket.emit(\"process-pid-completed\", process.pid);\n  });\n\n  socket.on(\"process-arch\", () => {\n    const value = process.arch;\n    electronSocket.emit(\"process-arch-completed\", value);\n  });\n\n  socket.on(\"process-platform\", () => {\n    const value = process.platform;\n    electronSocket.emit(\"process-platform-completed\", value);\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/screen.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"register-screen-display-added\", (id) => {\n        electron_1.screen.on(\"display-added\", (event, display) => {\n            electronSocket.emit(\"screen-display-added\" + id, display);\n        });\n    });\n    socket.on(\"register-screen-display-removed\", (id) => {\n        electron_1.screen.on(\"display-removed\", (event, display) => {\n            electronSocket.emit(\"screen-display-removed\" + id, display);\n        });\n    });\n    socket.on(\"register-screen-display-metrics-changed\", (id) => {\n        electron_1.screen.on(\"display-metrics-changed\", (event, display, changedMetrics) => {\n            electronSocket.emit(\"screen-display-metrics-changed\" + id, [\n                display,\n                changedMetrics,\n            ]);\n        });\n    });\n    socket.on(\"screen-getCursorScreenPoint\", () => {\n        const point = electron_1.screen.getCursorScreenPoint();\n        electronSocket.emit(\"screen-getCursorScreenPoint-completed\", point);\n    });\n    socket.on(\"screen-getMenuBarWorkArea\", () => {\n        const height = electron_1.screen.getPrimaryDisplay().workArea;\n        electronSocket.emit(\"screen-getMenuBarWorkArea-completed\", height);\n    });\n    socket.on(\"screen-getPrimaryDisplay\", () => {\n        const display = electron_1.screen.getPrimaryDisplay();\n        electronSocket.emit(\"screen-getPrimaryDisplay-completed\", display);\n    });\n    socket.on(\"screen-getAllDisplays\", () => {\n        const display = electron_1.screen.getAllDisplays();\n        electronSocket.emit(\"screen-getAllDisplays-completed\", display);\n    });\n    socket.on(\"screen-getDisplayNearestPoint\", (point) => {\n        const display = electron_1.screen.getDisplayNearestPoint(point);\n        electronSocket.emit(\"screen-getDisplayNearestPoint-completed\", display);\n    });\n    socket.on(\"screen-getDisplayMatching\", (rectangle) => {\n        const display = electron_1.screen.getDisplayMatching(rectangle);\n        electronSocket.emit(\"screen-getDisplayMatching-completed\", display);\n    });\n};\n//# sourceMappingURL=screen.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/screen.ts",
    "content": "import type { Socket } from \"net\";\nimport { screen } from \"electron\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n\n  socket.on(\"register-screen-display-added\", (id) => {\n    screen.on(\"display-added\", (event, display) => {\n      electronSocket.emit(\"screen-display-added\" + id, display);\n    });\n  });\n\n  socket.on(\"register-screen-display-removed\", (id) => {\n    screen.on(\"display-removed\", (event, display) => {\n      electronSocket.emit(\"screen-display-removed\" + id, display);\n    });\n  });\n\n  socket.on(\"register-screen-display-metrics-changed\", (id) => {\n    screen.on(\"display-metrics-changed\", (event, display, changedMetrics) => {\n      electronSocket.emit(\"screen-display-metrics-changed\" + id, [\n        display,\n        changedMetrics,\n      ]);\n    });\n  });\n\n  socket.on(\"screen-getCursorScreenPoint\", () => {\n    const point = screen.getCursorScreenPoint();\n    electronSocket.emit(\"screen-getCursorScreenPoint-completed\", point);\n  });\n\n  socket.on(\"screen-getMenuBarWorkArea\", () => {\n    const height = screen.getPrimaryDisplay().workArea;\n    electronSocket.emit(\"screen-getMenuBarWorkArea-completed\", height);\n  });\n\n  socket.on(\"screen-getPrimaryDisplay\", () => {\n    const display = screen.getPrimaryDisplay();\n    electronSocket.emit(\"screen-getPrimaryDisplay-completed\", display);\n  });\n\n  socket.on(\"screen-getAllDisplays\", () => {\n    const display = screen.getAllDisplays();\n    electronSocket.emit(\"screen-getAllDisplays-completed\", display);\n  });\n\n  socket.on(\"screen-getDisplayNearestPoint\", (point) => {\n    const display = screen.getDisplayNearestPoint(point);\n    electronSocket.emit(\"screen-getDisplayNearestPoint-completed\", display);\n  });\n\n  socket.on(\"screen-getDisplayMatching\", (rectangle) => {\n    const display = screen.getDisplayMatching(rectangle);\n    electronSocket.emit(\"screen-getDisplayMatching-completed\", display);\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/shell.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"shell-showItemInFolder\", (fullPath) => {\n        electron_1.shell.showItemInFolder(fullPath);\n        electronSocket.emit(\"shell-showItemInFolderCompleted\");\n    });\n    socket.on(\"shell-openPath\", async (path) => {\n        const errorMessage = await electron_1.shell.openPath(path);\n        electronSocket.emit(\"shell-openPathCompleted\", errorMessage);\n    });\n    socket.on(\"shell-openExternal\", async (url, options) => {\n        let result = \"\";\n        if (options) {\n            await electron_1.shell.openExternal(url, options).catch((e) => {\n                result = e.message;\n            });\n        }\n        else {\n            await electron_1.shell.openExternal(url).catch((e) => {\n                result = e.message;\n            });\n        }\n        electronSocket.emit(\"shell-openExternalCompleted\", result);\n    });\n    socket.on(\"shell-trashItem\", async (fullPath, deleteOnFail) => {\n        let success = false;\n        try {\n            await electron_1.shell.trashItem(fullPath);\n            success = true;\n        }\n        catch (error) {\n            success = false;\n        }\n        electronSocket.emit(\"shell-trashItem-completed\", success);\n    });\n    socket.on(\"shell-beep\", () => {\n        electron_1.shell.beep();\n    });\n    socket.on(\"shell-writeShortcutLink\", (shortcutPath, operation, options) => {\n        const success = electron_1.shell.writeShortcutLink(shortcutPath, operation, options);\n        electronSocket.emit(\"shell-writeShortcutLinkCompleted\", success);\n    });\n    socket.on(\"shell-readShortcutLink\", (shortcutPath) => {\n        const shortcutDetails = electron_1.shell.readShortcutLink(shortcutPath);\n        electronSocket.emit(\"shell-readShortcutLinkCompleted\", shortcutDetails);\n    });\n};\n//# sourceMappingURL=shell.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/shell.ts",
    "content": "import type { Socket } from \"net\";\nimport { shell } from \"electron\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n  socket.on(\"shell-showItemInFolder\", (fullPath) => {\n    shell.showItemInFolder(fullPath);\n\n    electronSocket.emit(\"shell-showItemInFolderCompleted\");\n  });\n\n  socket.on(\"shell-openPath\", async (path) => {\n    const errorMessage = await shell.openPath(path);\n\n    electronSocket.emit(\"shell-openPathCompleted\", errorMessage);\n  });\n\n  socket.on(\"shell-openExternal\", async (url, options) => {\n    let result = \"\";\n\n    if (options) {\n      await shell.openExternal(url, options).catch((e) => {\n        result = e.message;\n      });\n    } else {\n      await shell.openExternal(url).catch((e) => {\n        result = e.message;\n      });\n    }\n\n    electronSocket.emit(\"shell-openExternalCompleted\", result);\n  });\n\n  socket.on(\"shell-trashItem\", async (fullPath, deleteOnFail) => {\n    let success = false;\n\n    try {\n      await shell.trashItem(fullPath);\n      success = true;\n    } catch (error) {\n      success = false;\n    }\n\n    electronSocket.emit(\"shell-trashItem-completed\", success);\n  });\n\n  socket.on(\"shell-beep\", () => {\n    shell.beep();\n  });\n\n  socket.on(\"shell-writeShortcutLink\", (shortcutPath, operation, options) => {\n    const success = shell.writeShortcutLink(shortcutPath, operation, options);\n\n    electronSocket.emit(\"shell-writeShortcutLinkCompleted\", success);\n  });\n\n  socket.on(\"shell-readShortcutLink\", (shortcutPath) => {\n    const shortcutDetails = shell.readShortcutLink(shortcutPath);\n\n    electronSocket.emit(\"shell-readShortcutLinkCompleted\", shortcutDetails);\n  });\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/tray.js",
    "content": "\"use strict\";\nconst electron_1 = require(\"electron\");\nlet tray = (global[\"$tray\"] = global[\"tray\"] || {\n    value: null,\n});\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    socket.on(\"register-tray-click\", (id) => {\n        if (tray.value) {\n            tray.value.on(\"click\", (event, bounds) => {\n                electronSocket.emit(\"tray-click\" + id, [\n                    event.__proto__,\n                    bounds,\n                ]);\n            });\n        }\n    });\n    socket.on(\"register-tray-right-click\", (id) => {\n        if (tray.value) {\n            tray.value.on(\"right-click\", (event, bounds) => {\n                electronSocket.emit(\"tray-right-click\" + id, [\n                    event.__proto__,\n                    bounds,\n                ]);\n            });\n        }\n    });\n    socket.on(\"register-tray-double-click\", (id) => {\n        if (tray.value) {\n            tray.value.on(\"double-click\", (event, bounds) => {\n                electronSocket.emit(\"tray-double-click\" + id, [\n                    event.__proto__,\n                    bounds,\n                ]);\n            });\n        }\n    });\n    socket.on(\"register-tray-balloon-show\", (id) => {\n        if (tray.value) {\n            tray.value.on(\"balloon-show\", () => {\n                electronSocket.emit(\"tray-balloon-show\" + id);\n            });\n        }\n    });\n    socket.on(\"register-tray-balloon-click\", (id) => {\n        if (tray.value) {\n            tray.value.on(\"balloon-click\", () => {\n                electronSocket.emit(\"tray-balloon-click\" + id);\n            });\n        }\n    });\n    socket.on(\"register-tray-balloon-closed\", (id) => {\n        if (tray.value) {\n            tray.value.on(\"balloon-closed\", () => {\n                electronSocket.emit(\"tray-balloon-closed\" + id);\n            });\n        }\n    });\n    socket.on(\"create-tray\", (image, menuItems) => {\n        const trayIcon = electron_1.nativeImage.createFromPath(image);\n        tray.value = new electron_1.Tray(trayIcon);\n        if (menuItems) {\n            applyContextMenu(menuItems);\n        }\n    });\n    socket.on(\"tray-destroy\", () => {\n        if (tray.value) {\n            tray.value.destroy();\n        }\n    });\n    socket.on(\"set-contextMenu\", (menuItems) => {\n        if (menuItems && tray.value) {\n            applyContextMenu(menuItems);\n        }\n    });\n    socket.on(\"tray-setImage\", (image) => {\n        if (tray.value) {\n            tray.value.setImage(image);\n        }\n    });\n    socket.on(\"tray-setPressedImage\", (image) => {\n        if (tray.value) {\n            const img = electron_1.nativeImage.createFromPath(image);\n            tray.value.setPressedImage(img);\n        }\n    });\n    socket.on(\"tray-setToolTip\", (toolTip) => {\n        if (tray.value) {\n            tray.value.setToolTip(toolTip);\n        }\n    });\n    socket.on(\"tray-setTitle\", (title) => {\n        if (tray.value) {\n            tray.value.setTitle(title);\n        }\n    });\n    socket.on(\"tray-displayBalloon\", (options) => {\n        if (tray.value) {\n            tray.value.displayBalloon(options);\n        }\n    });\n    socket.on(\"tray-isDestroyed\", () => {\n        if (tray.value) {\n            const isDestroyed = tray.value.isDestroyed();\n            electronSocket.emit(\"tray-isDestroyedCompleted\", isDestroyed);\n        }\n    });\n    socket.on(\"register-tray-on-event\", (eventName, listenerName) => {\n        if (tray.value) {\n            tray.value.on(eventName, (...args) => {\n                if (args.length > 1) {\n                    electronSocket.emit(listenerName, args[1]);\n                }\n                else {\n                    electronSocket.emit(listenerName);\n                }\n            });\n        }\n    });\n    socket.on(\"register-tray-once-event\", (eventName, listenerName) => {\n        if (tray.value) {\n            tray.value.once(eventName, (...args) => {\n                if (args.length > 1) {\n                    electronSocket.emit(listenerName, args[1]);\n                }\n                else {\n                    electronSocket.emit(listenerName);\n                }\n            });\n        }\n    });\n    function applyContextMenu(menuItems) {\n        const menu = electron_1.Menu.buildFromTemplate(menuItems);\n        addMenuItemClickConnector(menu.items, (id) => {\n            electronSocket.emit(\"trayMenuItemClicked\", id);\n        });\n        tray.value.setContextMenu(menu);\n    }\n    function addMenuItemClickConnector(menuItems, callback) {\n        menuItems.forEach((item) => {\n            if (item.submenu && item.submenu.items.length > 0) {\n                addMenuItemClickConnector(item.submenu.items, callback);\n            }\n            if (\"id\" in item && item.id) {\n                item.click = () => {\n                    callback(item.id);\n                };\n            }\n        });\n    }\n};\n//# sourceMappingURL=tray.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/tray.ts",
    "content": "import type { Socket } from \"net\";\nimport { Menu, Tray, nativeImage } from \"electron\";\n\nlet tray: { value: Electron.Tray } = (global[\"$tray\"] = global[\"tray\"] || {\n  value: null,\n});\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n  socket.on(\"register-tray-click\", (id) => {\n    if (tray.value) {\n      tray.value.on(\"click\", (event, bounds) => {\n        electronSocket.emit(\"tray-click\" + id, [\n          (<any>event).__proto__,\n          bounds,\n        ]);\n      });\n    }\n  });\n\n  socket.on(\"register-tray-right-click\", (id) => {\n    if (tray.value) {\n      tray.value.on(\"right-click\", (event, bounds) => {\n        electronSocket.emit(\"tray-right-click\" + id, [\n          (<any>event).__proto__,\n          bounds,\n        ]);\n      });\n    }\n  });\n\n  socket.on(\"register-tray-double-click\", (id) => {\n    if (tray.value) {\n      tray.value.on(\"double-click\", (event, bounds) => {\n        electronSocket.emit(\"tray-double-click\" + id, [\n          (<any>event).__proto__,\n          bounds,\n        ]);\n      });\n    }\n  });\n\n  socket.on(\"register-tray-balloon-show\", (id) => {\n    if (tray.value) {\n      tray.value.on(\"balloon-show\", () => {\n        electronSocket.emit(\"tray-balloon-show\" + id);\n      });\n    }\n  });\n\n  socket.on(\"register-tray-balloon-click\", (id) => {\n    if (tray.value) {\n      tray.value.on(\"balloon-click\", () => {\n        electronSocket.emit(\"tray-balloon-click\" + id);\n      });\n    }\n  });\n\n  socket.on(\"register-tray-balloon-closed\", (id) => {\n    if (tray.value) {\n      tray.value.on(\"balloon-closed\", () => {\n        electronSocket.emit(\"tray-balloon-closed\" + id);\n      });\n    }\n  });\n\n  socket.on(\"create-tray\", (image, menuItems) => {\n    const trayIcon = nativeImage.createFromPath(image);\n\n    tray.value = new Tray(trayIcon);\n\n    if (menuItems) {\n      applyContextMenu(menuItems);\n    }\n  });\n\n  socket.on(\"tray-destroy\", () => {\n    if (tray.value) {\n      tray.value.destroy();\n    }\n  });\n\n  socket.on(\"set-contextMenu\", (menuItems) => {\n    if (menuItems && tray.value) {\n      applyContextMenu(menuItems);\n    }\n  });\n\n  socket.on(\"tray-setImage\", (image) => {\n    if (tray.value) {\n      tray.value.setImage(image);\n    }\n  });\n\n  socket.on(\"tray-setPressedImage\", (image) => {\n    if (tray.value) {\n      const img = nativeImage.createFromPath(image);\n      tray.value.setPressedImage(img);\n    }\n  });\n\n  socket.on(\"tray-setToolTip\", (toolTip) => {\n    if (tray.value) {\n      tray.value.setToolTip(toolTip);\n    }\n  });\n\n  socket.on(\"tray-setTitle\", (title) => {\n    if (tray.value) {\n      tray.value.setTitle(title);\n    }\n  });\n\n  socket.on(\"tray-displayBalloon\", (options) => {\n    if (tray.value) {\n      tray.value.displayBalloon(options);\n    }\n  });\n\n  socket.on(\"tray-isDestroyed\", () => {\n    if (tray.value) {\n      const isDestroyed = tray.value.isDestroyed();\n      electronSocket.emit(\"tray-isDestroyedCompleted\", isDestroyed);\n    }\n  });\n\n  socket.on(\"register-tray-on-event\", (eventName, listenerName) => {\n    if (tray.value) {\n      tray.value.on(eventName, (...args: any[]) => {\n        if (args.length > 1) {\n          electronSocket.emit(listenerName, args[1]);\n        } else {\n          electronSocket.emit(listenerName);\n        }\n      });\n    }\n  });\n\n  socket.on(\"register-tray-once-event\", (eventName, listenerName) => {\n    if (tray.value) {\n      tray.value.once(eventName, (...args: any[]) => {\n        if (args.length > 1) {\n          electronSocket.emit(listenerName, args[1]);\n        } else {\n          electronSocket.emit(listenerName);\n        }\n      });\n    }\n  });\n\n  function applyContextMenu(menuItems) {\n    const menu = Menu.buildFromTemplate(menuItems);\n    addMenuItemClickConnector(menu.items, (id) => {\n      electronSocket.emit(\"trayMenuItemClicked\", id);\n    });\n    tray.value.setContextMenu(menu);\n  }\n\n  function addMenuItemClickConnector(menuItems, callback) {\n    menuItems.forEach((item) => {\n      if (item.submenu && item.submenu.items.length > 0) {\n        addMenuItemClickConnector(item.submenu.items, callback);\n      }\n\n      if (\"id\" in item && item.id) {\n        item.click = () => {\n          callback(item.id);\n        };\n      }\n    });\n  }\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/api/webContents.js",
    "content": "\"use strict\";\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n    if (k2 === undefined) k2 = k;\n    var desc = Object.getOwnPropertyDescriptor(m, k);\n    if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n      desc = { enumerable: true, get: function() { return m[k]; } };\n    }\n    Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n    if (k2 === undefined) k2 = k;\n    o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n    Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n    o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || (function () {\n    var ownKeys = function(o) {\n        ownKeys = Object.getOwnPropertyNames || function (o) {\n            var ar = [];\n            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\n            return ar;\n        };\n        return ownKeys(o);\n    };\n    return function (mod) {\n        if (mod && mod.__esModule) return mod;\n        var result = {};\n        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\n        __setModuleDefault(result, mod);\n        return result;\n    };\n})();\nconst fs = __importStar(require(\"fs\"));\nconst electron_1 = require(\"electron\");\nconst browserView_1 = require(\"./browserView\");\nlet electronSocket;\nmodule.exports = (socket) => {\n    electronSocket = socket;\n    // The crashed event has been removed in Electron 29\n    socket.on(\"register-webContents-crashed\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.removeAllListeners(\"crashed\");\n        // @ts-expect-error No overload matches this call\n        browserWindow.webContents.on(\"crashed\", (event, killed) => {\n            electronSocket.emit(\"webContents-crashed\" + id, killed);\n        });\n    });\n    socket.on(\"register-webContents-didFinishLoad\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.removeAllListeners(\"did-finish-load\");\n        browserWindow.webContents.on(\"did-finish-load\", () => {\n            electronSocket.emit(\"webContents-didFinishLoad\" + id);\n        });\n    });\n    socket.on(\"register-webContents-didStartNavigation\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.removeAllListeners(\"did-start-navigation\");\n        browserWindow.webContents.on(\"did-start-navigation\", (_, url) => {\n            electronSocket.emit(\"webContents-didStartNavigation\" + id, url);\n        });\n    });\n    socket.on(\"register-webContents-didNavigate\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.removeAllListeners(\"did-navigate\");\n        browserWindow.webContents.on(\"did-navigate\", (_, url, httpResponseCode) => {\n            electronSocket.emit(\"webContents-didNavigate\" + id, {\n                url,\n                httpResponseCode,\n            });\n        });\n    });\n    socket.on(\"register-webContents-willRedirect\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.removeAllListeners(\"will-redirect\");\n        browserWindow.webContents.on(\"will-redirect\", (_, url) => {\n            electronSocket.emit(\"webContents-willRedirect\" + id, url);\n        });\n    });\n    socket.on(\"register-webContents-didFailLoad\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.removeAllListeners(\"did-fail-load\");\n        browserWindow.webContents.on(\"did-fail-load\", (_, errorCode, validatedUrl) => {\n            electronSocket.emit(\"webContents-didFailLoad\" + id, {\n                errorCode,\n                validatedUrl,\n            });\n        });\n    });\n    socket.on(\"register-webContents-didRedirectNavigation\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.removeAllListeners(\"did-redirect-navigation\");\n        browserWindow.webContents.on(\"did-redirect-navigation\", (_, url) => {\n            electronSocket.emit(\"webContents-didRedirectNavigation\" + id, url);\n        });\n    });\n    socket.on(\"register-webContents-input-event\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.removeAllListeners(\"input-event\");\n        browserWindow.webContents.on(\"input-event\", (_, eventArgs) => {\n            if (eventArgs.type !== \"char\") {\n                electronSocket.emit(\"webContents-input-event\" + id, eventArgs);\n            }\n        });\n    });\n    socket.on(\"register-webContents-domReady\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.removeAllListeners(\"dom-ready\");\n        browserWindow.webContents.on(\"dom-ready\", () => {\n            electronSocket.emit(\"webContents-domReady\" + id);\n        });\n    });\n    socket.on(\"webContents-openDevTools\", (id, options) => {\n        if (options) {\n            getWindowById(id).webContents.openDevTools(options);\n        }\n        else {\n            getWindowById(id).webContents.openDevTools();\n        }\n    });\n    socket.on(\"webContents-getPrinters\", async (id) => {\n        const printers = await getWindowById(id).webContents.getPrintersAsync();\n        electronSocket.emit(\"webContents-getPrinters-completed\", printers);\n    });\n    socket.on(\"webContents-print\", async (id, options = {}) => {\n        await getWindowById(id).webContents.print(options);\n        electronSocket.emit(\"webContents-print-completed\", true);\n    });\n    socket.on(\"webContents-printToPDF\", async (id, options = {}, path) => {\n        const buffer = await getWindowById(id).webContents.printToPDF(options);\n        fs.writeFile(path, buffer, (error) => {\n            if (error) {\n                electronSocket.emit(\"webContents-printToPDF-completed\", false);\n            }\n            else {\n                electronSocket.emit(\"webContents-printToPDF-completed\", true);\n            }\n        });\n    });\n    socket.on(\"webContents-executeJavaScript\", async (id, code, userGesture = false) => {\n        const result = await getWindowById(id).webContents.executeJavaScript(code, userGesture);\n        electronSocket.emit(\"webContents-executeJavaScript-completed\", result);\n    });\n    socket.on(\"webContents-getUrl\", function (id) {\n        const browserWindow = getWindowById(id);\n        electronSocket.emit(\"webContents-getUrl\" + id, browserWindow.webContents.getURL());\n    });\n    socket.on(\"webContents-session-allowNTLMCredentialsForDomains\", (id, domains) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.allowNTLMCredentialsForDomains(domains);\n    });\n    socket.on(\"webContents-session-clearAuthCache\", async (...args) => {\n        // Overload support: (id, guid) OR (id, options, guid)\n        const browserWindow = getWindowById(args[0]);\n        let guid;\n        if (args.length === 2) {\n            // No options\n            guid = args[1];\n            await browserWindow.webContents.session.clearAuthCache();\n        }\n        else if (args.length === 3) {\n            const options = args[1];\n            guid = args[2];\n            try {\n                // @ts-ignore\n                await browserWindow.webContents.session.clearAuthCache(options);\n            }\n            catch {\n                // Fallback to clearing without options if Electron version rejects custom options\n                await browserWindow.webContents.session.clearAuthCache();\n            }\n        }\n        else {\n            return; // invalid invocation\n        }\n        electronSocket.emit(\"webContents-session-clearAuthCache-completed\" + guid);\n    });\n    socket.on(\"webContents-session-clearCache\", async (id, guid) => {\n        const browserWindow = getWindowById(id);\n        await browserWindow.webContents.session.clearCache();\n        electronSocket.emit(\"webContents-session-clearCache-completed\" + guid);\n    });\n    socket.on(\"webContents-session-clearHostResolverCache\", async (id, guid) => {\n        const browserWindow = getWindowById(id);\n        await browserWindow.webContents.session.clearHostResolverCache();\n        electronSocket.emit(\"webContents-session-clearHostResolverCache-completed\" + guid);\n    });\n    socket.on(\"webContents-session-clearStorageData\", async (id, guid) => {\n        const browserWindow = getWindowById(id);\n        await browserWindow.webContents.session.clearStorageData({});\n        electronSocket.emit(\"webContents-session-clearStorageData-completed\" + guid);\n    });\n    socket.on(\"webContents-session-clearStorageData-options\", async (id, options, guid) => {\n        const browserWindow = getWindowById(id);\n        await browserWindow.webContents.session.clearStorageData(options);\n        electronSocket.emit(\"webContents-session-clearStorageData-options-completed\" + guid);\n    });\n    socket.on(\"webContents-session-createInterruptedDownload\", (id, options) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.createInterruptedDownload(options);\n    });\n    socket.on(\"webContents-session-disableNetworkEmulation\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.disableNetworkEmulation();\n    });\n    socket.on(\"webContents-session-enableNetworkEmulation\", (id, options) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.enableNetworkEmulation(options);\n    });\n    socket.on(\"webContents-session-flushStorageData\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.flushStorageData();\n    });\n    socket.on(\"webContents-session-getBlobData\", async (id, identifier, guid) => {\n        const browserWindow = getWindowById(id);\n        const buffer = await browserWindow.webContents.session.getBlobData(identifier);\n        electronSocket.emit(\"webContents-session-getBlobData-completed\" + guid, buffer.buffer);\n    });\n    socket.on(\"webContents-session-getCacheSize\", async (id, guid) => {\n        const browserWindow = getWindowById(id);\n        const size = await browserWindow.webContents.session.getCacheSize();\n        electronSocket.emit(\"webContents-session-getCacheSize-completed\" + guid, size);\n    });\n    socket.on(\"webContents-session-getPreloads\", (id, guid) => {\n        const browserWindow = getWindowById(id);\n        const preloads = browserWindow.webContents.session.getPreloads();\n        electronSocket.emit(\"webContents-session-getPreloads-completed\" + guid, preloads);\n    });\n    socket.on(\"webContents-session-getUserAgent\", (id, guid) => {\n        const browserWindow = getWindowById(id);\n        const userAgent = browserWindow.webContents.session.getUserAgent();\n        electronSocket.emit(\"webContents-session-getUserAgent-completed\" + guid, userAgent);\n    });\n    socket.on(\"webContents-session-resolveProxy\", async (id, url, guid) => {\n        const browserWindow = getWindowById(id);\n        const proxy = await browserWindow.webContents.session.resolveProxy(url);\n        electronSocket.emit(\"webContents-session-resolveProxy-completed\" + guid, proxy);\n    });\n    socket.on(\"webContents-session-setDownloadPath\", (id, path) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.setDownloadPath(path);\n    });\n    socket.on(\"webContents-session-setPreloads\", (id, preloads) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.setPreloads(preloads);\n    });\n    socket.on(\"webContents-session-setProxy\", async (id, configuration, guid) => {\n        const browserWindow = getWindowById(id);\n        await browserWindow.webContents.session.setProxy(configuration);\n        electronSocket.emit(\"webContents-session-setProxy-completed\" + guid);\n    });\n    socket.on(\"webContents-session-setUserAgent\", (id, userAgent, acceptLanguages) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.setUserAgent(userAgent, acceptLanguages);\n    });\n    socket.on(\"register-webContents-session-webRequest-onBeforeRequest\", (id, filter) => {\n        const browserWindow = getWindowById(id);\n        const session = browserWindow.webContents.session;\n        session.webRequest.onBeforeRequest(filter, (details, callback) => {\n            socket.emit(`webContents-session-webRequest-onBeforeRequest${id}`, details);\n            // Listen for a response from C# to continue the request\n            electronSocket.once(`webContents-session-webRequest-onBeforeRequest-response${id}`, (response) => {\n                callback(response);\n            });\n        });\n    });\n    socket.on(\"register-webContents-session-cookies-changed\", (id) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.cookies.removeAllListeners(\"changed\");\n        browserWindow.webContents.session.cookies.on(\"changed\", (event, cookie, cause, removed) => {\n            electronSocket.emit(\"webContents-session-cookies-changed\" + id, [\n                cookie,\n                cause,\n                removed,\n            ]);\n        });\n    });\n    socket.on(\"webContents-session-cookies-get\", async (id, filter, guid) => {\n        const browserWindow = getWindowById(id);\n        const cookies = await browserWindow.webContents.session.cookies.get(filter);\n        electronSocket.emit(\"webContents-session-cookies-get-completed\" + guid, cookies);\n    });\n    socket.on(\"webContents-session-cookies-set\", async (id, details, guid) => {\n        const browserWindow = getWindowById(id);\n        await browserWindow.webContents.session.cookies.set(details);\n        electronSocket.emit(\"webContents-session-cookies-set-completed\" + guid);\n    });\n    socket.on(\"webContents-session-cookies-remove\", async (id, url, name, guid) => {\n        const browserWindow = getWindowById(id);\n        await browserWindow.webContents.session.cookies.remove(url, name);\n        electronSocket.emit(\"webContents-session-cookies-remove-completed\" + guid);\n    });\n    socket.on(\"webContents-session-cookies-flushStore\", async (id, guid) => {\n        const browserWindow = getWindowById(id);\n        await browserWindow.webContents.session.cookies.flushStore();\n        electronSocket.emit(\"webContents-session-cookies-flushStore-completed\" + guid);\n    });\n    socket.on(\"webContents-loadURL\", (id, url, options) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents\n            .loadURL(url, options)\n            .then(() => {\n            electronSocket.emit(\"webContents-loadURL-complete\" + id);\n        })\n            .catch((error) => {\n            console.error(error);\n            electronSocket.emit(\"webContents-loadURL-error\" + id, error);\n        });\n    });\n    socket.on(\"webContents-insertCSS\", (id, isBrowserWindow, path) => {\n        if (isBrowserWindow) {\n            const browserWindow = getWindowById(id);\n            if (browserWindow) {\n                browserWindow.webContents.insertCSS(fs.readFileSync(path, \"utf8\"));\n            }\n        }\n        else {\n            const browserViews = (global[\"browserViews\"] =\n                global[\"browserViews\"] || []);\n            let view = null;\n            for (let i = 0; i < browserViews.length; i++) {\n                if (browserViews[i][\"id\"] + 1000 === id) {\n                    view = browserViews[i];\n                    break;\n                }\n            }\n            if (view) {\n                view.webContents.insertCSS(fs.readFileSync(path, \"utf8\"));\n            }\n        }\n    });\n    socket.on(\"webContents-session-getAllExtensions\", (id) => {\n        const browserWindow = getWindowById(id);\n        const extensionsList = browserWindow.webContents.session.getAllExtensions();\n        const chromeExtensionInfo = [];\n        Object.keys(extensionsList).forEach((key) => {\n            chromeExtensionInfo.push(extensionsList[key]);\n        });\n        electronSocket.emit(\"webContents-session-getAllExtensions-completed\", chromeExtensionInfo);\n    });\n    socket.on(\"webContents-session-removeExtension\", (id, name) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.session.removeExtension(name);\n    });\n    socket.on(\"webContents-session-loadExtension\", async (id, path, allowFileAccess = false) => {\n        const browserWindow = getWindowById(id);\n        const extension = await browserWindow.webContents.session.loadExtension(path, { allowFileAccess: allowFileAccess });\n        electronSocket.emit(\"webContents-session-loadExtension-completed\", extension);\n    });\n    socket.on(\"webContents-getZoomFactor\", (id) => {\n        const browserWindow = getWindowById(id);\n        const text = browserWindow.webContents.getZoomFactor();\n        electronSocket.emit(\"webContents-getZoomFactor-completed\", text);\n    });\n    socket.on(\"webContents-setZoomFactor\", (id, factor) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.setZoomFactor(factor);\n    });\n    socket.on(\"webContents-getZoomLevel\", (id) => {\n        const browserWindow = getWindowById(id);\n        const content = browserWindow.webContents.getZoomLevel();\n        electronSocket.emit(\"webContents-getZoomLevel-completed\", content);\n    });\n    socket.on(\"webContents-setZoomLevel\", (id, level) => {\n        const browserWindow = getWindowById(id);\n        browserWindow.webContents.setZoomLevel(level);\n    });\n    socket.on(\"webContents-setVisualZoomLevelLimits\", async (id, minimumLevel, maximumLevel) => {\n        const browserWindow = getWindowById(id);\n        await browserWindow.webContents.setVisualZoomLevelLimits(minimumLevel, maximumLevel);\n        electronSocket.emit(\"webContents-setVisualZoomLevelLimits-completed\");\n    });\n    socket.on(\"webContents-toggleDevTools\", (id) => {\n        getWindowById(id).webContents.toggleDevTools();\n    });\n    socket.on(\"webContents-closeDevTools\", (id) => {\n        getWindowById(id).webContents.closeDevTools();\n    });\n    socket.on(\"webContents-isDevToolsOpened\", function (id) {\n        const browserWindow = getWindowById(id);\n        electronSocket.emit(\"webContents-isDevToolsOpened-completed\", browserWindow.webContents.isDevToolsOpened());\n    });\n    socket.on(\"webContents-isDevToolsFocused\", function (id) {\n        const browserWindow = getWindowById(id);\n        electronSocket.emit(\"webContents-isDevToolsFocused-completed\", browserWindow.webContents.isDevToolsFocused());\n    });\n    socket.on(\"webContents-setAudioMuted\", (id, muted) => {\n        getWindowById(id).webContents.setAudioMuted(muted);\n    });\n    socket.on(\"webContents-isAudioMuted\", function (id) {\n        const browserWindow = getWindowById(id);\n        electronSocket.emit(\"webContents-isAudioMuted-completed\", browserWindow.webContents.isAudioMuted());\n    });\n    socket.on(\"webContents-isCurrentlyAudible\", function (id) {\n        const browserWindow = getWindowById(id);\n        electronSocket.emit(\"webContents-isCurrentlyAudible-completed\", browserWindow.webContents.isCurrentlyAudible());\n    });\n    socket.on(\"webContents-getUserAgent\", function (id) {\n        const browserWindow = getWindowById(id);\n        electronSocket.emit(\"webContents-getUserAgent-completed\", browserWindow.webContents.getUserAgent());\n    });\n    socket.on(\"webContents-setUserAgent\", (id, userAgent) => {\n        getWindowById(id).webContents.setUserAgent(userAgent);\n    });\n    function getWindowById(id) {\n        if (id >= 1000) {\n            return (0, browserView_1.browserViewMediateService)(id - 1000);\n        }\n        return electron_1.BrowserWindow.fromId(id);\n    }\n};\n//# sourceMappingURL=webContents.js.map"
  },
  {
    "path": "src/ElectronNET.Host/api/webContents.ts",
    "content": "import * as fs from \"fs\";\nimport type { Socket } from \"net\";\nimport { BrowserWindow, BrowserView } from \"electron\";\n\nimport { browserViewMediateService } from \"./browserView\";\n\nlet electronSocket: Socket;\n\nexport = (socket: Socket) => {\n  electronSocket = socket;\n\n  // The crashed event has been removed in Electron 29\n  socket.on(\"register-webContents-crashed\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.removeAllListeners(\"crashed\");\n    // @ts-expect-error No overload matches this call\n    browserWindow.webContents.on(\"crashed\", (event, killed) => {\n      electronSocket.emit(\"webContents-crashed\" + id, killed);\n    });\n  });\n\n  socket.on(\"register-webContents-didFinishLoad\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.removeAllListeners(\"did-finish-load\");\n    browserWindow.webContents.on(\"did-finish-load\", () => {\n      electronSocket.emit(\"webContents-didFinishLoad\" + id);\n    });\n  });\n\n  socket.on(\"register-webContents-didStartNavigation\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.removeAllListeners(\"did-start-navigation\");\n    browserWindow.webContents.on(\"did-start-navigation\", (_, url) => {\n      electronSocket.emit(\"webContents-didStartNavigation\" + id, url);\n    });\n  });\n\n  socket.on(\"register-webContents-didNavigate\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.removeAllListeners(\"did-navigate\");\n    browserWindow.webContents.on(\"did-navigate\", (_, url, httpResponseCode) => {\n      electronSocket.emit(\"webContents-didNavigate\" + id, {\n        url,\n        httpResponseCode,\n      });\n    });\n  });\n\n  socket.on(\"register-webContents-willRedirect\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.removeAllListeners(\"will-redirect\");\n    browserWindow.webContents.on(\"will-redirect\", (_, url) => {\n      electronSocket.emit(\"webContents-willRedirect\" + id, url);\n    });\n  });\n\n  socket.on(\"register-webContents-didFailLoad\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.removeAllListeners(\"did-fail-load\");\n    browserWindow.webContents.on(\n      \"did-fail-load\",\n      (_, errorCode, validatedUrl) => {\n        electronSocket.emit(\"webContents-didFailLoad\" + id, {\n          errorCode,\n          validatedUrl,\n        });\n      },\n    );\n  });\n\n  socket.on(\"register-webContents-didRedirectNavigation\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.removeAllListeners(\"did-redirect-navigation\");\n    browserWindow.webContents.on(\"did-redirect-navigation\", (_, url) => {\n      electronSocket.emit(\"webContents-didRedirectNavigation\" + id, url);\n    });\n  });\n\n  socket.on(\"register-webContents-input-event\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.removeAllListeners(\"input-event\");\n    browserWindow.webContents.on(\"input-event\", (_, eventArgs) => {\n      if (eventArgs.type !== \"char\") {\n        electronSocket.emit(\"webContents-input-event\" + id, eventArgs);\n      }\n    });\n  });\n\n  socket.on(\"register-webContents-domReady\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.removeAllListeners(\"dom-ready\");\n    browserWindow.webContents.on(\"dom-ready\", () => {\n      electronSocket.emit(\"webContents-domReady\" + id);\n    });\n  });\n\n  socket.on(\"webContents-openDevTools\", (id, options) => {\n    if (options) {\n      getWindowById(id).webContents.openDevTools(options);\n    } else {\n      getWindowById(id).webContents.openDevTools();\n    }\n  });\n\n  socket.on(\"webContents-getPrinters\", async (id) => {\n    const printers = await getWindowById(id).webContents.getPrintersAsync();\n    electronSocket.emit(\"webContents-getPrinters-completed\", printers);\n  });\n\n  socket.on(\"webContents-print\", async (id, options = {}) => {\n    await getWindowById(id).webContents.print(options);\n    electronSocket.emit(\"webContents-print-completed\", true);\n  });\n\n  socket.on(\"webContents-printToPDF\", async (id, options = {}, path) => {\n    const buffer = await getWindowById(id).webContents.printToPDF(options);\n\n    fs.writeFile(path, buffer, (error) => {\n      if (error) {\n        electronSocket.emit(\"webContents-printToPDF-completed\", false);\n      } else {\n        electronSocket.emit(\"webContents-printToPDF-completed\", true);\n      }\n    });\n  });\n\n  socket.on(\n    \"webContents-executeJavaScript\",\n    async (id, code, userGesture = false) => {\n      const result = await getWindowById(id).webContents.executeJavaScript(\n        code,\n        userGesture,\n      );\n      electronSocket.emit(\"webContents-executeJavaScript-completed\", result);\n    },\n  );\n\n  socket.on(\"webContents-getUrl\", function (id) {\n    const browserWindow = getWindowById(id);\n    electronSocket.emit(\n      \"webContents-getUrl\" + id,\n      browserWindow.webContents.getURL(),\n    );\n  });\n\n  socket.on(\n    \"webContents-session-allowNTLMCredentialsForDomains\",\n    (id, domains) => {\n      const browserWindow = getWindowById(id);\n      browserWindow.webContents.session.allowNTLMCredentialsForDomains(domains);\n    },\n  );\n\n  socket.on(\"webContents-session-clearAuthCache\", async (...args) => {\n    // Overload support: (id, guid) OR (id, options, guid)\n    const browserWindow = getWindowById(args[0]);\n    let guid: string;\n    if (args.length === 2) {\n      // No options\n      guid = args[1];\n      await browserWindow.webContents.session.clearAuthCache();\n    } else if (args.length === 3) {\n      const options = args[1];\n      guid = args[2];\n      try {\n        // @ts-ignore\n        await browserWindow.webContents.session.clearAuthCache(options);\n      } catch {\n        // Fallback to clearing without options if Electron version rejects custom options\n        await browserWindow.webContents.session.clearAuthCache();\n      }\n    } else {\n      return; // invalid invocation\n    }\n    electronSocket.emit(\"webContents-session-clearAuthCache-completed\" + guid);\n  });\n\n  socket.on(\"webContents-session-clearCache\", async (id, guid) => {\n    const browserWindow = getWindowById(id);\n    await browserWindow.webContents.session.clearCache();\n\n    electronSocket.emit(\"webContents-session-clearCache-completed\" + guid);\n  });\n\n  socket.on(\"webContents-session-clearHostResolverCache\", async (id, guid) => {\n    const browserWindow = getWindowById(id);\n    await browserWindow.webContents.session.clearHostResolverCache();\n\n    electronSocket.emit(\n      \"webContents-session-clearHostResolverCache-completed\" + guid,\n    );\n  });\n\n  socket.on(\"webContents-session-clearStorageData\", async (id, guid) => {\n    const browserWindow = getWindowById(id);\n    await browserWindow.webContents.session.clearStorageData({});\n\n    electronSocket.emit(\n      \"webContents-session-clearStorageData-completed\" + guid,\n    );\n  });\n\n  socket.on(\n    \"webContents-session-clearStorageData-options\",\n    async (id, options, guid) => {\n      const browserWindow = getWindowById(id);\n      await browserWindow.webContents.session.clearStorageData(options);\n\n      electronSocket.emit(\n        \"webContents-session-clearStorageData-options-completed\" + guid,\n      );\n    },\n  );\n\n  socket.on(\"webContents-session-createInterruptedDownload\", (id, options) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents.session.createInterruptedDownload(options);\n  });\n\n  socket.on(\"webContents-session-disableNetworkEmulation\", (id) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents.session.disableNetworkEmulation();\n  });\n\n  socket.on(\"webContents-session-enableNetworkEmulation\", (id, options) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents.session.enableNetworkEmulation(options);\n  });\n\n  socket.on(\"webContents-session-flushStorageData\", (id) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents.session.flushStorageData();\n  });\n\n  socket.on(\"webContents-session-getBlobData\", async (id, identifier, guid) => {\n    const browserWindow = getWindowById(id);\n    const buffer =\n      await browserWindow.webContents.session.getBlobData(identifier);\n\n    electronSocket.emit(\n      \"webContents-session-getBlobData-completed\" + guid,\n      buffer.buffer,\n    );\n  });\n\n  socket.on(\"webContents-session-getCacheSize\", async (id, guid) => {\n    const browserWindow = getWindowById(id);\n    const size = await browserWindow.webContents.session.getCacheSize();\n\n    electronSocket.emit(\n      \"webContents-session-getCacheSize-completed\" + guid,\n      size,\n    );\n  });\n\n  socket.on(\"webContents-session-getPreloads\", (id, guid) => {\n    const browserWindow = getWindowById(id);\n    const preloads = browserWindow.webContents.session.getPreloads();\n\n    electronSocket.emit(\n      \"webContents-session-getPreloads-completed\" + guid,\n      preloads,\n    );\n  });\n\n  socket.on(\"webContents-session-getUserAgent\", (id, guid) => {\n    const browserWindow = getWindowById(id);\n    const userAgent = browserWindow.webContents.session.getUserAgent();\n\n    electronSocket.emit(\n      \"webContents-session-getUserAgent-completed\" + guid,\n      userAgent,\n    );\n  });\n\n  socket.on(\"webContents-session-resolveProxy\", async (id, url, guid) => {\n    const browserWindow = getWindowById(id);\n    const proxy = await browserWindow.webContents.session.resolveProxy(url);\n\n    electronSocket.emit(\n      \"webContents-session-resolveProxy-completed\" + guid,\n      proxy,\n    );\n  });\n\n  socket.on(\"webContents-session-setDownloadPath\", (id, path) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents.session.setDownloadPath(path);\n  });\n\n  socket.on(\"webContents-session-setPreloads\", (id, preloads) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents.session.setPreloads(preloads);\n  });\n\n  socket.on(\"webContents-session-setProxy\", async (id, configuration, guid) => {\n    const browserWindow = getWindowById(id);\n    await browserWindow.webContents.session.setProxy(configuration);\n\n    electronSocket.emit(\"webContents-session-setProxy-completed\" + guid);\n  });\n\n  socket.on(\n    \"webContents-session-setUserAgent\",\n    (id, userAgent, acceptLanguages) => {\n      const browserWindow = getWindowById(id);\n      browserWindow.webContents.session.setUserAgent(\n        userAgent,\n        acceptLanguages,\n      );\n    },\n  );\n\n  socket.on(\n    \"register-webContents-session-webRequest-onBeforeRequest\",\n    (id, filter) => {\n      const browserWindow = getWindowById(id);\n      const session = browserWindow.webContents.session;\n\n      session.webRequest.onBeforeRequest(filter, (details, callback) => {\n        socket.emit(\n          `webContents-session-webRequest-onBeforeRequest${id}`,\n          details,\n        );\n        // Listen for a response from C# to continue the request\n        electronSocket.once(\n          `webContents-session-webRequest-onBeforeRequest-response${id}`,\n          (response) => {\n            callback(response);\n          },\n        );\n      });\n    },\n  );\n\n  socket.on(\"register-webContents-session-cookies-changed\", (id) => {\n    const browserWindow = getWindowById(id);\n\n    browserWindow.webContents.session.cookies.removeAllListeners(\"changed\");\n    browserWindow.webContents.session.cookies.on(\n      \"changed\",\n      (event, cookie, cause, removed) => {\n        electronSocket.emit(\"webContents-session-cookies-changed\" + id, [\n          cookie,\n          cause,\n          removed,\n        ]);\n      },\n    );\n  });\n\n  socket.on(\"webContents-session-cookies-get\", async (id, filter, guid) => {\n    const browserWindow = getWindowById(id);\n    const cookies = await browserWindow.webContents.session.cookies.get(filter);\n\n    electronSocket.emit(\n      \"webContents-session-cookies-get-completed\" + guid,\n      cookies,\n    );\n  });\n\n  socket.on(\"webContents-session-cookies-set\", async (id, details, guid) => {\n    const browserWindow = getWindowById(id);\n    await browserWindow.webContents.session.cookies.set(details);\n\n    electronSocket.emit(\"webContents-session-cookies-set-completed\" + guid);\n  });\n\n  socket.on(\n    \"webContents-session-cookies-remove\",\n    async (id, url, name, guid) => {\n      const browserWindow = getWindowById(id);\n      await browserWindow.webContents.session.cookies.remove(url, name);\n\n      electronSocket.emit(\n        \"webContents-session-cookies-remove-completed\" + guid,\n      );\n    },\n  );\n\n  socket.on(\"webContents-session-cookies-flushStore\", async (id, guid) => {\n    const browserWindow = getWindowById(id);\n    await browserWindow.webContents.session.cookies.flushStore();\n\n    electronSocket.emit(\n      \"webContents-session-cookies-flushStore-completed\" + guid,\n    );\n  });\n\n  socket.on(\"webContents-loadURL\", (id, url, options) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents\n      .loadURL(url, options)\n      .then(() => {\n        electronSocket.emit(\"webContents-loadURL-complete\" + id);\n      })\n      .catch((error) => {\n        console.error(error);\n        electronSocket.emit(\"webContents-loadURL-error\" + id, error);\n      });\n  });\n\n  socket.on(\"webContents-insertCSS\", (id, isBrowserWindow, path) => {\n    if (isBrowserWindow) {\n      const browserWindow = getWindowById(id);\n      if (browserWindow) {\n        browserWindow.webContents.insertCSS(fs.readFileSync(path, \"utf8\"));\n      }\n    } else {\n      const browserViews: BrowserView[] = (global[\"browserViews\"] =\n        global[\"browserViews\"] || []) as BrowserView[];\n      let view: BrowserView = null;\n      for (let i = 0; i < browserViews.length; i++) {\n        if (browserViews[i][\"id\"] + 1000 === id) {\n          view = browserViews[i];\n          break;\n        }\n      }\n      if (view) {\n        view.webContents.insertCSS(fs.readFileSync(path, \"utf8\"));\n      }\n    }\n  });\n\n  socket.on(\"webContents-session-getAllExtensions\", (id) => {\n    const browserWindow = getWindowById(id);\n    const extensionsList = browserWindow.webContents.session.getAllExtensions();\n    const chromeExtensionInfo = [];\n\n    Object.keys(extensionsList).forEach((key) => {\n      chromeExtensionInfo.push(extensionsList[key]);\n    });\n\n    electronSocket.emit(\n      \"webContents-session-getAllExtensions-completed\",\n      chromeExtensionInfo,\n    );\n  });\n\n  socket.on(\"webContents-session-removeExtension\", (id, name) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents.session.removeExtension(name);\n  });\n\n  socket.on(\n    \"webContents-session-loadExtension\",\n    async (id, path, allowFileAccess = false) => {\n      const browserWindow = getWindowById(id);\n      const extension = await browserWindow.webContents.session.loadExtension(\n        path,\n        { allowFileAccess: allowFileAccess },\n      );\n\n      electronSocket.emit(\n        \"webContents-session-loadExtension-completed\",\n        extension,\n      );\n    },\n  );\n\n  socket.on(\"webContents-getZoomFactor\", (id) => {\n    const browserWindow = getWindowById(id);\n    const text = browserWindow.webContents.getZoomFactor();\n    electronSocket.emit(\"webContents-getZoomFactor-completed\", text);\n  });\n\n  socket.on(\"webContents-setZoomFactor\", (id, factor) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents.setZoomFactor(factor);\n  });\n\n  socket.on(\"webContents-getZoomLevel\", (id) => {\n    const browserWindow = getWindowById(id);\n    const content = browserWindow.webContents.getZoomLevel();\n    electronSocket.emit(\"webContents-getZoomLevel-completed\", content);\n  });\n\n  socket.on(\"webContents-setZoomLevel\", (id, level) => {\n    const browserWindow = getWindowById(id);\n    browserWindow.webContents.setZoomLevel(level);\n  });\n\n  socket.on(\n    \"webContents-setVisualZoomLevelLimits\",\n    async (id, minimumLevel, maximumLevel) => {\n      const browserWindow = getWindowById(id);\n      await browserWindow.webContents.setVisualZoomLevelLimits(\n        minimumLevel,\n        maximumLevel,\n      );\n      electronSocket.emit(\"webContents-setVisualZoomLevelLimits-completed\");\n    },\n  );\n\n  socket.on(\"webContents-toggleDevTools\", (id) => {\n    getWindowById(id).webContents.toggleDevTools();\n  });\n\n  socket.on(\"webContents-closeDevTools\", (id) => {\n    getWindowById(id).webContents.closeDevTools();\n  });\n\n  socket.on(\"webContents-isDevToolsOpened\", function (id) {\n    const browserWindow = getWindowById(id);\n    electronSocket.emit(\n      \"webContents-isDevToolsOpened-completed\",\n      browserWindow.webContents.isDevToolsOpened(),\n    );\n  });\n\n  socket.on(\"webContents-isDevToolsFocused\", function (id) {\n    const browserWindow = getWindowById(id);\n    electronSocket.emit(\n      \"webContents-isDevToolsFocused-completed\",\n      browserWindow.webContents.isDevToolsFocused(),\n    );\n  });\n\n  socket.on(\"webContents-setAudioMuted\", (id, muted) => {\n    getWindowById(id).webContents.setAudioMuted(muted);\n  });\n\n  socket.on(\"webContents-isAudioMuted\", function (id) {\n    const browserWindow = getWindowById(id);\n    electronSocket.emit(\n      \"webContents-isAudioMuted-completed\",\n      browserWindow.webContents.isAudioMuted(),\n    );\n  });\n\n  socket.on(\"webContents-isCurrentlyAudible\", function (id) {\n    const browserWindow = getWindowById(id);\n    electronSocket.emit(\n      \"webContents-isCurrentlyAudible-completed\",\n      browserWindow.webContents.isCurrentlyAudible(),\n    );\n  });\n\n  socket.on(\"webContents-getUserAgent\", function (id) {\n    const browserWindow = getWindowById(id);\n    electronSocket.emit(\n      \"webContents-getUserAgent-completed\",\n      browserWindow.webContents.getUserAgent(),\n    );\n  });\n\n  socket.on(\"webContents-setUserAgent\", (id, userAgent) => {\n    getWindowById(id).webContents.setUserAgent(userAgent);\n  });\n\n  function getWindowById(\n    id: number,\n  ): Electron.BrowserWindow | Electron.BrowserView {\n    if (id >= 1000) {\n      return browserViewMediateService(id - 1000);\n    }\n\n    return BrowserWindow.fromId(id);\n  }\n};\n"
  },
  {
    "path": "src/ElectronNET.Host/eslint.config.js",
    "content": "module.exports = [\n    {\n        rules: {\n            // Add rules here.\n        }\n    }\n];"
  },
  {
    "path": "src/ElectronNET.Host/globals.d.ts",
    "content": "// Ambient declarations to silence implicit any / global index usage\n// Minimal surface  expand only if further errors appear.\ndeclare var browserViews: any;\ndeclare var tray: any;\ndeclare var electronsocket: any;\n"
  },
  {
    "path": "src/ElectronNET.Host/main.js",
    "content": "﻿const { app } = require('electron');\nconst { BrowserWindow } = require('electron');\nconst { protocol } = require('electron');\nconst path = require('path');\nconst cProcess = require('child_process').spawn;\nconst portscanner = require('portscanner');\nconst { imageSize } = require('image-size');\nlet io, server, browserWindows, ipc, apiProcess, loadURL;\nlet appApi, menu, dialogApi, notification, tray, webContents;\nlet globalShortcut, shellApi, screen, clipboard, autoUpdater;\nlet commandLine, browserView;\nlet powerMonitor;\nlet processInfo;\nlet splashScreen;\nlet nativeTheme;\nlet dock;\nlet launchFile;\nlet launchUrl;\nlet processApi;\n\nlet manifestJsonFileName = 'package.json';\nlet unpackedelectron = false;\nlet unpackeddotnet = false;\nlet dotnetpacked = false;\nlet electronforcedport;\n\nif (app.commandLine.hasSwitch('manifest')) {\n    manifestJsonFileName = app.commandLine.getSwitchValue('manifest');\n}\n\nconsole.log('Entry!!!:  ');\n\nif (app.commandLine.hasSwitch('unpackedelectron')) {\n    unpackedelectron = true;\n}\nelse if (app.commandLine.hasSwitch('unpackeddotnet')) {\n    unpackeddotnet = true;\n}\nelse if (app.commandLine.hasSwitch('dotnetpacked')) {\n    dotnetpacked = true;\n}\n\nif (app.commandLine.hasSwitch('electronforcedport')) {\n    electronforcedport = app.commandLine.getSwitchValue('electronforcedport');\n}\n\n// Custom startup hook: look for custom_main.js and invoke its onStartup(host) if present.\n// If the hook returns false, abort Electron startup.\ntry {\n    const fs = require('fs');\n    const customMainPath = path.join(__dirname, 'custom_main.js');\n    if (fs.existsSync(customMainPath)) {\n        const customMain = require(customMainPath);\n        if (customMain && typeof customMain.onStartup === 'function') {\n            const continueStartup = customMain.onStartup(globalThis);\n            if (continueStartup === false) {\n                ////console.log('custom_main.js onStartup returned false. Exiting Electron host.');\n                // Ensure the app terminates immediately before further initialization.\n                // Use app.exit to allow Electron to perform its shutdown, fallback to process.exit.\n                try { app.exit(0); } catch (err) { process.exit(0); }\n            }\n        } else {\n            console.warn('custom_main.js found but no onStartup function exported.');\n        }\n    }\n} catch (err) {\n    console.error('Error while executing custom_main.js:', err);\n}\n\nconst currentPath = __dirname;\nlet currentBinPath = path.join(currentPath.replace('app.asar', ''), 'bin');\nlet manifestJsonFilePath = path.join(currentPath, manifestJsonFileName);\n\n// if running unpackedelectron, lets change the path\nif (unpackedelectron || unpackeddotnet) {\n    console.log('unpackedelectron! dir: ' + currentPath);\n\n    manifestJsonFilePath = path.join(currentPath, manifestJsonFileName);\n    currentBinPath = path.join(currentPath, '../'); // go to project directory\n}\n\n//  handle macOS events for opening the app with a file, etc\napp.on('will-finish-launching', () => {\n    app.on('open-file', (evt, file) => {\n        evt.preventDefault();\n        launchFile = file;\n    });\n    app.on('open-url', (evt, url) => {\n        evt.preventDefault();\n        launchUrl = url;\n    });\n});\n\nconst manifestJsonFile = require(manifestJsonFilePath);\n\nif (manifestJsonFile.singleInstance) {\n    const mainInstance = app.requestSingleInstanceLock();\n    app.on('second-instance', (events, args = []) => {\n        args.forEach((parameter) => {\n            const words = parameter.split('=');\n\n            if (words.length > 1) {\n                app.commandLine.appendSwitch(words[0].replace('--', ''), words[1]);\n            } else {\n                app.commandLine.appendSwitch(words[0].replace('--', ''));\n            }\n        });\n\n        const windows = BrowserWindow.getAllWindows();\n        if (windows.length) {\n            if (windows[0].isMinimized()) {\n                windows[0].restore();\n            }\n            windows[0].focus();\n        }\n    });\n\n    if (!mainInstance) {\n        app.quit();\n    }\n}\n\n// Collect user supplied command line args (excluding those handled by Electron host itself)\nfunction getForwardedArgs() {\n    const skipSwitches = new Set(['unpackedelectron', 'unpackeddotnet', 'dotnetpacked']);\n    return process.argv.slice(2).filter(arg => {\n        if (!arg) return false;\n        // Node/Electron internal or we already process them\n        if (arg.startsWith('--manifest')) return false;\n        const cleaned = arg.replace(/^--/, '').replace(/^\\//, '');\n        if (skipSwitches.has(cleaned)) return false;\n        if (cleaned.startsWith('inspect')) return false;\n        if (cleaned.startsWith('remote-debugging-port')) return false;\n        // We add /electronPort ourselves later\n        if (cleaned.startsWith('electronPort=')) return false;\n        if (cleaned.startsWith('electronWebPort=')) return false;\n        return true;\n    });\n}\n\nconst forwardedArgs = getForwardedArgs();\n\napp.on('ready', () => {\n    // Fix ERR_UNKNOWN_URL_SCHEME using file protocol\n    // https://github.com/electron/electron/issues/23757\n    ////protocol.registerFileProtocol('file', (request, callback) => {\n    ////  const pathname = request.url.replace('file:///', '');\n    ////  callback(pathname);\n    ////});\n\n    if (isSplashScreenEnabled()) {\n        startSplashScreen();\n    }\n\n    if (electronforcedport) {\n        console.log('Electron Socket IO (forced) Port: ' + electronforcedport);\n        startSocketApiBridge(electronforcedport);\n        return;\n    }\n\n    // Added default port as configurable for port restricted environments.\n    let defaultElectronPort = 8000;\n    if (manifestJsonFile.electronPort) {\n        defaultElectronPort = manifestJsonFile.electronPort;\n    }\n\n    // hostname needs to be localhost, otherwise Windows Firewall will be triggered.\n    portscanner.findAPortNotInUse(defaultElectronPort, 65535, 'localhost', function (error, port) {\n        console.log('Electron Socket IO Port: ' + port);\n        startSocketApiBridge(port);\n    });\n});\n\napp.on('quit', async (event, exitCode) => {\n    try {\n        server.close();\n        server.closeAllConnections();\n    } catch (e) {\n        console.error(e);\n    }\n\n    try {\n        apiProcess?.kill();\n    } catch (e) {\n        console.error(e);\n    }\n\n    try {\n        if (io && typeof io.close === 'function') {\n            io.close();\n        }\n    } catch (e) {\n        console.error(e);\n    }\n});\n\nfunction isSplashScreenEnabled() {\n    if (manifestJsonFile.hasOwnProperty('splashscreen')) {\n        if (manifestJsonFile.splashscreen.hasOwnProperty('imageFile')) {\n            return Boolean(manifestJsonFile.splashscreen.imageFile);\n        }\n    }\n\n    return false;\n}\n\nfunction startSplashScreen() {\n    const imageFile = path.join(currentPath, manifestJsonFile.splashscreen.imageFile);\n    const isHtml = imageFile.endsWith('.html') || imageFile.endsWith('.htm');\n    const startWindow = (width, height) => {\n        splashScreen = new BrowserWindow({\n            width: width,\n            height: height,\n            transparent: true,\n            center: true,\n            frame: false,\n            closable: false,\n            resizable: false,\n            skipTaskbar: true,\n            alwaysOnTop: true,\n            show: true,\n        });\n        splashScreen.setIgnoreMouseEvents(true);\n\n        app.once('browser-window-created', () => {\n            splashScreen.destroy();\n        });\n\n        const loadSplashscreenUrl = isHtml ? imageFile : path.join(currentPath, 'splashscreen', 'index.html') + '?imgPath=' + imageFile;\n        splashScreen.loadURL('file://' + loadSplashscreenUrl);\n        splashScreen.once('closed', () => {\n            splashScreen = null;\n        });\n    };\n\n    if (manifestJsonFile.splashscreen.width && manifestJsonFile.splashscreen.height) {\n        // width and height are set explicitly\n        return startWindow(manifestJsonFile.splashscreen.width, manifestJsonFile.splashscreen.height);\n    }\n\n    if (isHtml) {\n        // we cannot compute width and height => use default\n        return startWindow(800, 600);\n    }\n\n    // it's an image, so we can compute the desired splash screen size\n    imageSize(imageFile, (error, dimensions) => {\n        if (error) {\n            console.log(`load splashscreen error:`);\n            console.error(error);\n\n            throw new Error(error.message);\n        }\n\n        startWindow(dimensions.width, dimensions.height);\n    });\n}\n\nfunction startSocketApiBridge(port) {\n    // instead of 'require('socket.io')(port);' we need to use this workaround\n    // otherwise the Windows Firewall will be triggered\n    console.log('Electron Socket: starting...');\n    server = require('http').createServer();\n    const { Server } = require('socket.io');\n    let hostHook;\n    io = new Server({\n        pingTimeout: 60000, // in ms, default is 5000\n        pingInterval: 10000, // in ms, default is 25000\n    });\n    io.attach(server);\n\n    server.listen(port, 'localhost');\n    server.on('listening', function () {\n        console.log('Electron Socket: listening on port %s at %s', server.address().port, server.address().address);\n        // Now that socket connection is established, we can guarantee port will not be open for portscanner\n        if (unpackedelectron) {\n            startAspCoreBackendUnpackaged(port);\n        } else if (!unpackeddotnet && !dotnetpacked) {\n            startAspCoreBackend(port);\n        }\n    });\n\n    // prototype\n    app['mainWindowURL'] = '';\n    app['mainWindow'] = null;\n\n    // @ts-ignore\n    io.on('connection', (socket) => {\n        console.log('Electron Socket: connected!');\n        socket.on('disconnect', function (reason) {\n            console.log('Got disconnect! Reason: ' + reason);\n            try {\n                ////console.log('requireCache');\n                ////console.log(require.cache['electron-host-hook']);\n\n                if (hostHook) {\n                    const hostHookScriptFilePath = path.join(currentPath, 'ElectronHostHook', 'index.js');\n                    delete require.cache[require.resolve(hostHookScriptFilePath)];\n                    hostHook = undefined;\n                }\n            } catch (err) {\n                console.error(err.message);\n            }\n        });\n\n        if (global['electronsocket'] === undefined) {\n            global['electronsocket'] = socket;\n            global['electronsocket'].setMaxListeners(0);\n        }\n\n        console.log('Electron Socket: loading components...');\n\n        if (appApi === undefined) appApi = require('./api/app')(socket, app);\n        if (browserWindows === undefined) browserWindows = require('./api/browserWindows')(socket, app);\n        if (commandLine === undefined) commandLine = require('./api/commandLine')(socket, app);\n        if (autoUpdater === undefined) autoUpdater = require('./api/autoUpdater')(socket);\n        if (ipc === undefined) ipc = require('./api/ipc')(socket);\n        if (menu === undefined) menu = require('./api/menu')(socket);\n        if (dialogApi === undefined) dialogApi = require('./api/dialog')(socket);\n        if (notification === undefined) notification = require('./api/notification')(socket);\n        if (tray === undefined) tray = require('./api/tray')(socket);\n        if (webContents === undefined) webContents = require('./api/webContents')(socket);\n        if (globalShortcut === undefined) globalShortcut = require('./api/globalShortcut')(socket);\n        if (shellApi === undefined) shellApi = require('./api/shell')(socket);\n        if (screen === undefined) screen = require('./api/screen')(socket);\n        if (clipboard === undefined) clipboard = require('./api/clipboard')(socket);\n        if (browserView === undefined) browserView = require('./api/browserView').browserViewApi(socket);\n        if (powerMonitor === undefined) powerMonitor = require('./api/powerMonitor')(socket);\n        if (nativeTheme === undefined) nativeTheme = require('./api/nativeTheme')(socket);\n        if (dock === undefined) dock = require('./api/dock')(socket);\n        if (processInfo === undefined) processInfo = require('./api/process')(socket);\n\n        socket.on('register-app-open-file', (id) => {\n            global['electronsocket'] = socket;\n\n            app.on('open-file', (event, file) => {\n                event.preventDefault();\n\n                global['electronsocket'].emit('app-open-file' + id, file);\n            });\n\n            if (launchFile) {\n                global['electronsocket'].emit('app-open-file' + id, launchFile);\n            }\n        });\n\n        socket.on('register-app-open-url', (id) => {\n            global['electronsocket'] = socket;\n\n            app.on('open-url', (event, url) => {\n                event.preventDefault();\n\n                global['electronsocket'].emit('app-open-url' + id, url);\n            });\n\n            if (launchUrl) {\n                global['electronsocket'].emit('app-open-url' + id, launchUrl);\n            }\n        });\n\n        try {\n            const { HookService } = require('electron-host-hook');\n\n            if (hostHook === undefined) {\n                hostHook = new HookService(socket, app);\n                hostHook.onHostReady();\n            }\n        } catch (error) {\n            console.error(error.message);\n        }\n\n        console.log('Electron Socket: startup complete.');\n    });\n}\n\nfunction startAspCoreBackend(electronPort) {\n    startBackend();\n\n    function startBackend() {\n        loadURL = `about:blank`;\n        const envParam = getEnvironmentParameter();\n        const parameters = [\n            envParam,\n            `/electronPort=${electronPort}`,\n            `/electronPID=${process.pid}`,\n            // forward user supplied args (avoid duplicate environment)\n            ...forwardedArgs.filter(a => !(envParam && a.startsWith('--environment=')))\n        ].filter(p => p);\n        let binaryFile = manifestJsonFile.executable;\n\n        const os = require('os');\n        if (os.platform() === 'win32') {\n            binaryFile = binaryFile + '.exe';\n        }\n\n        let binFilePath = path.join(currentBinPath, binaryFile);\n        var options = { cwd: currentBinPath };\n        console.log('Starting backend with parameters:', parameters.join(' '));\n        apiProcess = cProcess(binFilePath, parameters, options);\n\n        apiProcess.stdout.on('data', (data) => {\n            console.log(`stdout: ${data.toString()}`);\n        });\n    }\n}\n\nfunction startAspCoreBackendUnpackaged(electronPort) {\n    startBackend();\n\n    function startBackend() {\n        loadURL = `about:blank`;\n        const envParam = getEnvironmentParameter();\n        const parameters = [\n            envParam,\n            `/electronPort=${electronPort}`,\n            `/electronPID=${process.pid}`,\n            ...forwardedArgs.filter(a => !(envParam && a.startsWith('--environment=')))\n        ].filter(p => p);\n        let binaryFile = manifestJsonFile.executable;\n\n        const os = require('os');\n        if (os.platform() === 'win32') {\n            binaryFile = binaryFile + '.exe';\n        }\n\n        let binFilePath = path.join(currentBinPath, binaryFile);\n        var options = { cwd: currentBinPath };\n        console.log('Starting backend (unpackaged) with parameters:', parameters.join(' '));\n        apiProcess = cProcess(binFilePath, parameters, options);\n\n        apiProcess.stdout.on('data', (data) => {\n            console.log(`stdout: ${data.toString()}`);\n        });\n    }\n}\n\nfunction getEnvironmentParameter() {\n    if (manifestJsonFile.environment) {\n        return '--environment=' + manifestJsonFile.environment;\n    }\n\n    return '';\n}\n"
  },
  {
    "path": "src/ElectronNET.Host/package.json",
    "content": "{\n  \"name\": \"electron.net.host\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Electron-Host for Electron.NET.\",\n  \"repository\": {\n    \"url\": \"https://github.com/ElectronNET/Electron.NET\"\n  },\n  \"main\": \"main.js\",\n  \"type\": \"commonjs\",\n  \"scripts\": {\n    \"build\": \"tsc --build\",\n    \"clean\": \"tsc --build --clean\",\n    \"start\": \"tsc -p .\"\n  },\n  \"keywords\": [],\n  \"author\": \"Gregor Biswanger, Florian Rappl\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"dasherize\": \"^2.0.0\",\n    \"electron-host-hook\": \"file:./ElectronHostHook\",\n    \"image-size\": \"^1.2.1\",\n    \"portscanner\": \"^2.2.0\",\n    \"electron-updater\": \"^6.6.2\",\n    \"socket.io\": \"^4.8.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.18\",\n    \"electron\": \"^30.0.3\",\n    \"eslint\": \"^9.39.1\",\n    \"typescript\": \"^5.9.3\"\n  }\n}\n"
  },
  {
    "path": "src/ElectronNET.Host/scripts/blazor-preload.js",
    "content": "global.process = undefined;\nglobal.module = undefined;\n"
  },
  {
    "path": "src/ElectronNET.Host/splashscreen/index.html",
    "content": "﻿<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n   <meta charset=\"UTF-8\">\n   <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n   <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n   <title>Splashscreen</title>\n</head>\n\n<body>\n   <style>\n      body {\n         overflow: hidden;\n      }\n   </style>\n\n   <img draggable=\"false\" alt=\"splashscreen\" style=\"width: 100%; height: 100%; margin: 0\">\n\n   <script>\n      (() => {\n         const imgSrcPath = window.location.search.substr(1).split('=').pop();\n         const imageElement = document.getElementsByTagName('img')[0];\n         imageElement.setAttribute('src', imgSrcPath);\n      })();\n   </script>\n</body>\n\n</html>"
  },
  {
    "path": "src/ElectronNET.Host/tsconfig.json",
    "content": "{\n  \"exclude\": [\n    \"node_modules\",\n    \"ElectronHostHook\"\n  ],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"target\": \"es2020\",\n    \"lib\": [\"es2020\"],\n    \"types\": [\"node\"],\n    \"sourceMap\": true,\n    \"strict\": false,\n    \"noImplicitAny\": false,\n    \"skipLibCheck\": true,\n    \"isolatedModules\": false,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"electron-updater\": [\"node_modules/electron-updater/dist/index.d.ts\"]\n    }\n  },\n  \"include\": [\n    \"**/*.ts\",\n    \"types-shims.d.ts\",\n    \"globals.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "src/ElectronNET.Host/tsconfig.tsbuildinfo",
    "content": "{\"root\":[\"./globals.d.ts\",\"./types-shims.d.ts\",\"./api/app.ts\",\"./api/autoupdater.ts\",\"./api/browserview.ts\",\"./api/browserwindows.ts\",\"./api/clipboard.ts\",\"./api/commandline.ts\",\"./api/dialog.ts\",\"./api/dock.ts\",\"./api/globalshortcut.ts\",\"./api/ipc.ts\",\"./api/menu.ts\",\"./api/nativetheme.ts\",\"./api/notification.ts\",\"./api/powermonitor.ts\",\"./api/process.ts\",\"./api/screen.ts\",\"./api/shell.ts\",\"./api/tray.ts\",\"./api/webcontents.ts\"],\"version\":\"5.9.3\"}"
  },
  {
    "path": "src/ElectronNET.Host/types-shims.d.ts",
    "content": "// Simplified ambient module declarations to silence unresolved external module TS errors\n// and missing extended tsconfig references inside node_modules.\n// This is internal only.\ndeclare module 'electron-updater' {\n  export const autoUpdater: any;\n}\n\ndeclare module '@ljharb/tsconfig';\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Common/IntegrationFactAttribute.cs",
    "content": "﻿namespace ElectronNET.IntegrationTests.Common\n{\n    using System.Runtime.InteropServices;\n    using Xunit.Sdk;\n\n    /// <summary>\n    /// Custom fact attribute with a default timeout of 20 seconds, allowing tests to be skipped on specific environments.\n    /// </summary>\n    /// <seealso cref=\"Xunit.FactAttribute\" />\n    [AttributeUsage(AttributeTargets.Method)]\n    [XunitTestCaseDiscoverer(\"Xunit.Sdk.SkippableFactDiscoverer\", \"Xunit.SkippableFact\")]\n    internal sealed class IntegrationFactAttribute : FactAttribute\n    {\n        private static readonly bool IsOnWsl;\n\n        private static readonly bool IsOnCI;\n\n        static IntegrationFactAttribute()\n        {\n            IsOnWsl = DetectWsl();\n            IsOnCI = DetectCI();\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IntegrationFactAttribute\" /> class.\n        /// </summary>\n        public IntegrationFactAttribute()\n        {\n            this.Timeout = 20_000;\n        }\n\n        public bool SkipOnWsl { get; set; }\n\n        public bool SkipOnCI { get; set; }\n\n        /// <summary>\n        /// Marks the test so that it will not be run, and gets or sets the skip reason\n        /// </summary>\n        public override string Skip {\n            get\n            {\n                if (IsOnWsl && this.SkipOnWsl)\n                {\n                    return \"Skipping test on WSL environment.\";\n                }\n\n                if (IsOnCI && this.SkipOnCI)\n                {\n                    return \"Skipping test on CI environment.\";\n                }\n\n                return base.Skip;\n            }\n            set\n            {\n                base.Skip = value;\n            }\n        }\n\n        private static bool DetectWsl()\n        {\n            try\n            {\n                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\n                {\n                    return false;\n                }\n\n                if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(\"WSL_DISTRO_NAME\")) ||\n                    !string.IsNullOrEmpty(Environment.GetEnvironmentVariable(\"WSL_INTEROP\")))\n                {\n                    return true;\n                }\n\n                return false;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        private static bool DetectCI()\n        {\n            try\n            {\n                if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(\"TF_BUILD\")) ||\n                    !string.IsNullOrEmpty(Environment.GetEnvironmentVariable(\"GITHUB_ACTIONS\")))\n                {\n                    return true;\n                }\n\n                return false;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Common/IntegrationTestBase.cs",
    "content": "namespace ElectronNET.IntegrationTests.Common\n{\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n\n    // Base class for integration tests providing shared access to MainWindow and OS platform constants\n    public abstract class IntegrationTestBase\n    {\n        protected IntegrationTestBase(ElectronFixture fixture)\n        {\n            Fixture = fixture;\n            MainWindow = fixture.MainWindow;\n        }\n\n        protected ElectronFixture Fixture { get; }\n        protected BrowserWindow MainWindow { get; }\n\n        // Constants for SupportedOSPlatform attributes\n        public const string Windows = \"Windows\";\n        public const string MacOS = \"macOS\";\n        public const string Linux = \"Linux\";\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/ElectronFixture.cs",
    "content": "namespace ElectronNET.IntegrationTests\n{\n    using System.Diagnostics.CodeAnalysis;\n    using System.Reflection;\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n    using ElectronNET.Common;\n\n    // Shared fixture that starts Electron runtime once\n    [SuppressMessage(\"ReSharper\", \"MethodHasAsyncOverload\")]\n    public class ElectronFixture : IAsyncLifetime\n    {\n        public BrowserWindow MainWindow { get; private set; } = null!;\n\n        public async Task InitializeAsync()\n        {\n            try\n            {\n                Console.Error.WriteLine(\"[ElectronFixture] InitializeAsync: start\");\n                AppDomain.CurrentDomain.SetData(\"ElectronTestAssembly\", Assembly.GetExecutingAssembly());\n\n                Console.WriteLine(\"[ElectronFixture] Acquire RuntimeController\");\n                var runtimeController = ElectronNetRuntime.RuntimeController;\n                ElectronNetRuntime.ElectronExtraArguments = \"--no-sandbox\";\n\n                Console.Error.WriteLine(\"[ElectronFixture] Starting Electron runtime...\");\n                await runtimeController.Start();\n\n                Console.Error.WriteLine(\"[ElectronFixture] Waiting for Ready...\");\n                await Task.WhenAny(runtimeController.WaitReadyTask, Task.Delay(10.seconds()));\n\n                if (!runtimeController.WaitReadyTask.IsCompleted)\n                {\n                    throw new TimeoutException(\"The Electron process did not start within 10 seconds\");\n                }\n\n                Console.Error.WriteLine(\"[ElectronFixture] Runtime Ready\");\n\n                // create hidden window for tests (avoid showing UI)\n                this.MainWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions\n                {\n                    Show = false,\n                    Width = 800,\n                    Height = 600,\n                }, \"about:blank\");\n\n                await this.MainWindow.WebContents.Session.ClearCacheAsync();\n            }\n            catch (Exception ex)\n            {\n                Console.Error.WriteLine(\"[ElectronFixture] InitializeAsync: exception\");\n                Console.Error.WriteLine(ex.ToString());\n                throw;\n            }\n        }\n\n        public async Task DisposeAsync()\n        {\n            var runtimeController = ElectronNetRuntime.RuntimeController;\n            Console.Error.WriteLine(\"[ElectronFixture] Stopping Electron runtime...\");\n            await runtimeController.Stop();\n            await runtimeController.WaitStoppedTask;\n            Console.Error.WriteLine(\"[ElectronFixture] Runtime stopped\");\n        }\n    }\n\n    [CollectionDefinition(\"ElectronCollection\")]\n    public class ElectronCollection : ICollectionFixture<ElectronFixture>\n    {\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/ElectronNET.IntegrationTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <!-- When this is enabled, the project will be switched from nuget packages to consuming the ElectronNet orchestration directly -->\n    <ElectronNetDevMode>true</ElectronNetDevMode>\n  </PropertyGroup>\n\n  <Import Project=\"..\\ElectronNET\\build\\ElectronNET.Core.props\" Condition=\"$(ElectronNetDevMode)\" />\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>disable</Nullable>\n    <IsPackable>false</IsPackable>\n    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <!-- https://github.com/Tyrrrz/GitHubActionsTestLogger/issues/5 -->\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n    <PackageReference Include=\"GitHubActionsTestLogger\" Version=\"2.4.1\" PrivateAssets=\"all\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"FluentAssertions\" Version=\"8.8.0\" />\n    <PackageReference Include=\"Xunit.SkippableFact\" Version=\"1.5.23\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ElectronNET.API\\ElectronNET.API.csproj\" />\n    <ProjectReference Include=\"..\\ElectronNET\\ElectronNET.csproj\" />\n  </ItemGroup>\n\n  <PropertyGroup>\n    <!-- Disable test parallelization at runner level to avoid multiple Electron instances -->\n    <ParallelizeTestCollections>false</ParallelizeTestCollections>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Update=\"xunit.runner.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n  <Import Project=\"..\\ElectronNET\\build\\ElectronNET.Core.targets\" Condition=\"$(ElectronNetDevMode)\" />\n\n</Project>\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/GlobalUsings.cs",
    "content": "global using Xunit;\nglobal using FluentAssertions;"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Properties/electron-builder.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/electron-userland/electron-builder/refs/heads/master/packages/app-builder-lib/scheme.json\",\n  \"compression\": \"maximum\",\n  \"linux\": {\n    \"target\": [\n      \"tar.xz\"\n    ],\n    \"executableArgs\": [ \"--no-sandbox\" ],\n    \"artifactName\": \"${name}-${arch}-${version}.${ext}\"\n  },\n  \"win\": {\n    \"target\": [\n      {\n        \"target\": \"portable\",\n        \"arch\": \"x64\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/AppTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n    using System;\n    using System.IO;\n    using System.Runtime.Versioning;\n    using System.Threading.Tasks;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class AppTests : IntegrationTestBase\n    {\n        public AppTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Can_get_app_path()\n        {\n            var path = await Electron.App.GetAppPathAsync();\n            path.Should().NotBeNullOrWhiteSpace();\n            Directory.Exists(path).Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task Can_get_version_and_locale()\n        {\n            var version = await Electron.App.GetVersionAsync();\n            version.Should().NotBeNullOrWhiteSpace();\n            var locale = await Electron.App.GetLocaleAsync();\n            locale.Should().NotBeNullOrWhiteSpace();\n        }\n\n        [IntegrationFact]\n        public async Task Can_get_special_paths()\n        {\n            var userData = await Electron.App.GetPathAsync(PathName.UserData);\n            userData.Should().NotBeNullOrWhiteSpace();\n            Directory.Exists(Path.GetDirectoryName(userData) ?? userData).Should().BeTrue();\n\n            var temp = await Electron.App.GetPathAsync(PathName.Temp);\n            temp.Should().NotBeNullOrWhiteSpace();\n            Directory.Exists(temp).Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task Can_get_app_metrics()\n        {\n            var metrics = await Electron.App.GetAppMetricsAsync();\n            metrics.Should().NotBeNull();\n            metrics.Length.Should().BeGreaterThan(0);\n        }\n\n        [IntegrationFact]\n        public async Task Can_get_gpu_feature_status()\n        {\n            var status = await Electron.App.GetGpuFeatureStatusAsync();\n            status.Should().NotBeNull();\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(MacOS)]\n        [SupportedOSPlatform(Windows)]\n        public async Task Can_get_login_item_settings()\n        {\n            var settings = await Electron.App.GetLoginItemSettingsAsync();\n            settings.Should().NotBeNull();\n        }\n\n        [IntegrationFact]\n        public async Task CommandLine_append_and_query_switch()\n        {\n            var switchName = \"integration-switch\";\n            Electron.App.CommandLine.AppendSwitch(switchName, \"value123\");\n            (await Electron.App.CommandLine.HasSwitchAsync(switchName)).Should().BeTrue();\n            (await Electron.App.CommandLine.GetSwitchValueAsync(switchName)).Should().Be(\"value123\");\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(MacOS)]\n        [SupportedOSPlatform(Windows)]\n        public async Task Accessibility_support_toggle()\n        {\n            Electron.App.SetAccessibilitySupportEnabled(true);\n            var enabled = await Electron.App.IsAccessibilitySupportEnabledAsync();\n            enabled.Should().BeTrue(); // API responded\n            Electron.App.SetAccessibilitySupportEnabled(false);\n        }\n\n        [IntegrationFact]\n        public async Task UserAgentFallback_roundtrip()\n        {\n            var original = await Electron.App.UserAgentFallbackAsync;\n            Electron.App.UserAgentFallback = \"ElectronIntegrationTest/1.0\";\n            var updated = await Electron.App.UserAgentFallbackAsync;\n            updated.Should().Be(\"ElectronIntegrationTest/1.0\");\n            Electron.App.UserAgentFallback = original; // restore\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(Linux)]\n        [SupportedOSPlatform(MacOS)]\n        public async Task BadgeCount_set_and_reset_where_supported()\n        {\n            await Electron.App.SetBadgeCountAsync(2);\n            var count = await Electron.App.GetBadgeCountAsync();\n            // Some platforms may always return0; just ensure call didn't throw and is non-negative\n            count.Should().BeGreaterThanOrEqualTo(0);\n            await Electron.App.SetBadgeCountAsync(0);\n        }\n\n        [IntegrationFact]\n        public async Task App_metrics_have_cpu_info()\n        {\n            var metrics = await Electron.App.GetAppMetricsAsync();\n            metrics[0].Cpu.Should().NotBeNull();\n        }\n\n        [IntegrationFact]\n        public async Task App_gpu_feature_status_has_some_fields()\n        {\n            var status = await Electron.App.GetGpuFeatureStatusAsync();\n            status.Should().NotBeNull();\n            status.Webgl.Should().NotBeNull();\n            status.VideoDecode.Should().NotBeNull();\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/AutoUpdaterTests.cs",
    "content": "﻿namespace ElectronNET.IntegrationTests.Tests\n{\n    using API;\n    using System.Threading.Tasks;\n    using ElectronNET.Common;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class AutoUpdaterTests : IntegrationTestBase\n    {\n        public AutoUpdaterTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task AutoDownload_check()\n        {\n            Electron.AutoUpdater.AutoDownload = false;\n            var test1 = Electron.AutoUpdater.AutoDownload;\n            Electron.AutoUpdater.AutoDownload = true;\n            var test2 = Electron.AutoUpdater.AutoDownload;\n            test1.Should().BeFalse();\n            test2.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task AutoInstallOnAppQuit_check()\n        {\n            Electron.AutoUpdater.AutoInstallOnAppQuit = false;\n            var test1 = Electron.AutoUpdater.AutoInstallOnAppQuit;\n            Electron.AutoUpdater.AutoInstallOnAppQuit = true;\n            var test2 = Electron.AutoUpdater.AutoInstallOnAppQuit;\n            test1.Should().BeFalse();\n            test2.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task AllowPrerelease_check()\n        {\n            Electron.AutoUpdater.AllowPrerelease = false;\n            var test1 = Electron.AutoUpdater.AllowPrerelease;\n            Electron.AutoUpdater.AllowPrerelease = true;\n            var test2 = Electron.AutoUpdater.AllowPrerelease;\n            test1.Should().BeFalse();\n            test2.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task FullChangelog_check()\n        {\n            Electron.AutoUpdater.FullChangelog = false;\n            var test1 = Electron.AutoUpdater.FullChangelog;\n            Electron.AutoUpdater.FullChangelog = true;\n            var test2 = Electron.AutoUpdater.FullChangelog;\n            test1.Should().BeFalse();\n            test2.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task AllowDowngrade_check()\n        {\n            Electron.AutoUpdater.AllowDowngrade = false;\n            var test1 = Electron.AutoUpdater.AllowDowngrade;\n            Electron.AutoUpdater.AllowDowngrade = true;\n            var test2 = Electron.AutoUpdater.AllowDowngrade;\n            test1.Should().BeFalse();\n            test2.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task UpdateConfigPath_check()\n        {\n            var test1 = Electron.AutoUpdater.UpdateConfigPath;\n            test1.Should().Be(string.Empty);\n        }\n\n        [IntegrationFact]\n        public async Task CurrentVersionAsync_check()\n        {\n            var semver = await Electron.AutoUpdater.CurrentVersionAsync;\n            semver.Should().NotBeNull();\n            semver.Major.Should().BeGreaterThan(0);\n        }\n\n        [IntegrationFact]\n        public async Task ChannelAsync_check()\n        {\n            var test = await Electron.AutoUpdater.ChannelAsync;\n            test.Should().Be(string.Empty);\n            Electron.AutoUpdater.SetChannel = \"beta\";\n            await Task.Delay(500.ms());\n            test = await Electron.AutoUpdater.ChannelAsync;\n            test.Should().Be(\"beta\");\n        }\n\n        [IntegrationFact]\n        public async Task RequestHeadersAsync_check()\n        {\n            var headers = new Dictionary<string, string>\n            {\n                { \"key1\", \"value1\" },\n            };\n            var test = await Electron.AutoUpdater.RequestHeadersAsync;\n            test.Should().BeNull();\n            Electron.AutoUpdater.RequestHeaders = headers;\n            await Task.Delay(500.ms());\n            test = await Electron.AutoUpdater.RequestHeadersAsync;\n            test.Should().NotBeNull();\n            test.Count.Should().Be(1);\n            test[\"key1\"].Should().Be(\"value1\");\n        }\n\n        [IntegrationFact]\n        public async Task CheckForUpdatesAsync_check()\n        {\n            var test = await Electron.AutoUpdater.CheckForUpdatesAsync();\n            test.Should().BeNull();\n        }\n\n        [IntegrationFact]\n        public async Task CheckForUpdatesAndNotifyAsync_check()\n        {\n            var test = await Electron.AutoUpdater.CheckForUpdatesAsync();\n            test.Should().BeNull();\n        }\n\n        [IntegrationFact]\n        public async Task GetFeedURLAsync_check()\n        {\n            var test = await Electron.AutoUpdater.GetFeedURLAsync();\n            test.Should().Contain(\"Deprecated\");\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/BrowserViewTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class BrowserViewTests : IntegrationTestBase\n    {\n        public BrowserViewTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Create_browser_view_and_adjust_bounds()\n        {\n            var view = await Electron.WindowManager.CreateBrowserViewAsync(new BrowserViewConstructorOptions());\n            this.MainWindow.SetBrowserView(view);\n            view.Bounds = new Rectangle { X = 0, Y = 0, Width = 300, Height = 200 };\n            // Access bounds again (synchronous property fetch)\n            var current = view.Bounds;\n            current.Width.Should().Be(300);\n            current.Height.Should().Be(200);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/BrowserWindowTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using System.Runtime.Versioning;\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n    using ElectronNET.Common;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class BrowserWindowTests : IntegrationTestBase\n    {\n        public BrowserWindowTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Can_set_and_get_title()\n        {\n            const string title = \"Integration Test Title\";\n            this.MainWindow.SetTitle(title);\n            await Task.Delay(500.ms());\n            var roundTrip = await this.MainWindow.GetTitleAsync();\n            roundTrip.Should().Be(title);\n        }\n\n        [IntegrationFact]\n        public async Task Can_resize_and_get_size()\n        {\n            this.MainWindow.SetSize(643, 482);\n            await Task.Delay(500.ms());\n            var size = await this.MainWindow.GetSizeAsync();\n            size.Should().HaveCount(2);\n            size[0].Should().Be(643);\n            size[1].Should().Be(482);\n        }\n\n        [IntegrationFact]\n        public async Task Can_set_progress_bar_and_clear()\n        {\n            this.MainWindow.SetProgressBar(0.5);\n            // No direct getter; rely on absence of error. Try changing again.\n            this.MainWindow.SetProgressBar(-1); // clears\n            await Task.Delay(50.ms());\n        }\n\n        [IntegrationFact(SkipOnWsl = true)]\n        public async Task Can_set_and_get_position()\n        {\n            this.MainWindow.SetPosition(134, 246);\n            await Task.Delay(500.ms());\n            var pos = await this.MainWindow.GetPositionAsync();\n            pos.Should().BeEquivalentTo([134, 246]);\n        }\n\n        [IntegrationFact]\n        public async Task Can_set_and_get_bounds()\n        {\n            var bounds = new Rectangle { X = 10, Y = 20, Width = 400, Height = 300 };\n            this.MainWindow.SetBounds(bounds);\n            await Task.Delay(500.ms());\n            var round = await this.MainWindow.GetBoundsAsync();\n\n            round.Should().BeEquivalentTo(bounds);\n            round.Width.Should().Be(400);\n            round.Height.Should().Be(300);\n        }\n\n        [IntegrationFact]\n        public async Task Can_set_and_get_content_bounds()\n        {\n            var bounds = new Rectangle { X = 0, Y = 0, Width = 300, Height = 200 };\n            this.MainWindow.SetContentBounds(bounds);\n            await Task.Delay(500.ms());\n            var round = await this.MainWindow.GetContentBoundsAsync();\n            round.Width.Should().BeGreaterThan(0);\n            round.Height.Should().BeGreaterThan(0);\n        }\n\n        [IntegrationFact]\n        public async Task Show_hide_visibility_roundtrip()\n        {\n            BrowserWindow window = null;\n\n            try\n            {\n                window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, \"about:blank\");\n\n                await Task.Delay(100.ms());\n\n                window.Show();\n\n                await Task.Delay(500.ms());\n                (await window.IsVisibleAsync()).Should().BeTrue();\n\n                window.Hide();\n                await Task.Delay(500.ms());\n\n                (await window.IsVisibleAsync()).Should().BeFalse();\n            }\n            finally\n            {\n                window?.Destroy();\n            }\n        }\n\n        [IntegrationFact]\n        public async Task AlwaysOnTop_toggle_and_query()\n        {\n            this.MainWindow.SetAlwaysOnTop(true);\n            await Task.Delay(500.ms());\n            (await this.MainWindow.IsAlwaysOnTopAsync()).Should().BeTrue();\n            this.MainWindow.SetAlwaysOnTop(false);\n            await Task.Delay(500.ms());\n            (await this.MainWindow.IsAlwaysOnTopAsync()).Should().BeFalse();\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(Linux)]\n        [SupportedOSPlatform(Windows)]\n        public async Task MenuBar_auto_hide_and_visibility()\n        {\n            this.MainWindow.SetAutoHideMenuBar(true);\n            await Task.Delay(500.ms());\n            (await this.MainWindow.IsMenuBarAutoHideAsync()).Should().BeTrue();\n            this.MainWindow.SetMenuBarVisibility(false);\n            await Task.Delay(500.ms());\n            (await this.MainWindow.IsMenuBarVisibleAsync()).Should().BeFalse();\n            this.MainWindow.SetMenuBarVisibility(true);\n            await Task.Delay(500.ms());\n            (await this.MainWindow.IsMenuBarVisibleAsync()).Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task ReadyToShow_event_fires_after_content_ready()\n        {\n            BrowserWindow window = null;\n\n            try\n            {\n                window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false }, \"about:blank\");\n                var tcs = new TaskCompletionSource();\n                window.OnReadyToShow += () => tcs.TrySetResult();\n\n                // Trigger a navigation and wait for DOM ready so the renderer paints, which emits ready-to-show\n                var domReadyTcs = new TaskCompletionSource();\n                window.WebContents.OnDomReady += () => domReadyTcs.TrySetResult();\n                await Task.Delay(500.ms());\n                await window.WebContents.LoadURLAsync(\"about:blank\");\n                await domReadyTcs.Task;\n\n                var completed = await Task.WhenAny(tcs.Task, Task.Delay(3.seconds()));\n                completed.Should().Be(tcs.Task);\n            }\n            finally\n            {\n                window?.Destroy();\n            }\n        }\n\n        [IntegrationFact]\n        public async Task PageTitleUpdated_event_fires_on_title_change()\n        {\n            var window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, \"about:blank\");\n            var tcs = new TaskCompletionSource<string>();\n            window.OnPageTitleUpdated += title => tcs.TrySetResult(title);\n\n            // Navigate and wait for DOM ready, then change the document.title to trigger the event\n            var domReadyTcs = new TaskCompletionSource();\n            window.WebContents.OnDomReady += () => domReadyTcs.TrySetResult();\n            await Task.Delay(500.ms());\n            await window.WebContents.LoadURLAsync(\"about:blank\");\n            await domReadyTcs.Task;\n            await window.WebContents.ExecuteJavaScriptAsync<string>(\"document.title='NewTitle';\");\n\n            // Wait for event up to a short timeout\n            var completed2 = await Task.WhenAny(tcs.Task, Task.Delay(3.seconds()));\n            completed2.Should().Be(tcs.Task);\n            (await tcs.Task).Should().Be(\"NewTitle\");\n        }\n\n        [IntegrationFact]\n        public async Task Resize_event_fires_on_size_change()\n        {\n            var window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false }, \"about:blank\");\n            var resized = false;\n            window.OnResize += () => resized = true;\n            await Task.Delay(500.ms());\n            window.SetSize(500, 400);\n            await Task.Delay(300.ms());\n            resized.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task Progress_bar_and_always_on_top_toggle()\n        {\n            var win = this.MainWindow;\n            win.SetProgressBar(0.5);\n            await Task.Delay(50.ms());\n            win.SetProgressBar(0.8, new ProgressBarOptions());\n            await Task.Delay(50.ms());\n            win.SetAlwaysOnTop(true);\n            await Task.Delay(500.ms());\n            (await win.IsAlwaysOnTopAsync()).Should().BeTrue();\n            win.SetAlwaysOnTop(false);\n            await Task.Delay(500.ms());\n            (await win.IsAlwaysOnTopAsync()).Should().BeFalse();\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(Linux)]\n        [SupportedOSPlatform(Windows)]\n        public async Task Menu_bar_visibility_and_auto_hide()\n        {\n            var win = this.MainWindow;\n            win.SetAutoHideMenuBar(true);\n            await Task.Delay(500.ms());\n            (await win.IsMenuBarAutoHideAsync()).Should().BeTrue();\n            win.SetMenuBarVisibility(true);\n            await Task.Delay(500.ms());\n            (await win.IsMenuBarVisibleAsync()).Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task Parent_child_relationship_roundtrip()\n        {\n            var child = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = false, Width = 300, Height = 200 }, \"about:blank\");\n            this.MainWindow.SetParentWindow(null); // ensure top-level\n            child.SetParentWindow(this.MainWindow);\n            await Task.Delay(500.ms());\n            var parent = await child.GetParentWindowAsync();\n            parent.Id.Should().Be(this.MainWindow.Id);\n            var kids = await this.MainWindow.GetChildWindowsAsync();\n            kids.Select(k => k.Id).Should().Contain(child.Id);\n            child.Destroy();\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(MacOS)]\n        public async Task Represented_filename_and_edited_flags()\n        {\n            var win = this.MainWindow;\n            var temp = Path.Combine(Path.GetTempPath(), \"electronnet_test.txt\");\n            File.WriteAllText(temp, \"test\");\n            win.SetRepresentedFilename(temp);\n\n            await Task.Delay(500.ms());\n\n            var represented = await win.GetRepresentedFilenameAsync();\n            represented.Should().Be(temp);\n\n            win.SetDocumentEdited(true);\n\n            await Task.Delay(500.ms());\n\n            var edited = await win.IsDocumentEditedAsync();\n            edited.Should().BeTrue();\n\n            win.SetDocumentEdited(false);\n        }\n\n        [IntegrationFact]\n        public async Task BoundsChanged_event_fires_with_updated_bounds()\n        {\n            BrowserWindow window = null;\n\n            try\n            {\n                window = await Electron.WindowManager.CreateWindowAsync(\n                    new BrowserWindowOptions { Show = true, Width = 300, Height = 200 },\n                    \"about:blank\");\n\n                await Task.Delay(5.seconds());\n\n                var tcs = new TaskCompletionSource<Rectangle>(TaskCreationOptions.RunContinuationsAsynchronously);\n                window.OnBoundsChanged += bounds => tcs.TrySetResult(bounds);\n\n                await Task.Delay(500.ms());\n\n                var target = new Rectangle { X = 25, Y = 35, Width = 420, Height = 310 };\n                window.SetBounds(target);\n\n                var completed = await Task.WhenAny(tcs.Task, Task.Delay(3.seconds()));\n                completed.Should().Be(tcs.Task);\n\n                var observed = await tcs.Task;\n\n                observed.Width.Should().Be(target.Width);\n                observed.Height.Should().Be(target.Height);\n            }\n            finally\n            {\n                window?.Destroy();\n            }\n        }\n\n        [IntegrationFact]\n        public async Task BoundsChanged_event_can_fire_on_resize_of_existing_window()\n        {\n            var win = this.MainWindow;\n\n            var tcs = new TaskCompletionSource<Rectangle>(TaskCreationOptions.RunContinuationsAsynchronously);\n            win.OnBoundsChanged += bounds => tcs.TrySetResult(bounds);\n\n            await Task.Delay(500.ms());\n            win.SetBounds(new Rectangle { X = 10, Y = 10, Width = 560, Height = 440 });\n\n            var completed = await Task.WhenAny(tcs.Task, Task.Delay(3.seconds()));\n            completed.Should().Be(tcs.Task);\n\n            var boundsObserved = await tcs.Task;\n            boundsObserved.Width.Should().Be(560);\n            boundsObserved.Height.Should().Be(440);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/ClipboardTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using System.Runtime.Versioning;\n    using ElectronNET.API;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class ClipboardTests : IntegrationTestBase\n    {\n        public ClipboardTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Clipboard_text_roundtrip()\n        {\n            var text = $\"Hello Electron {Guid.NewGuid()}\";\n            Electron.Clipboard.WriteText(text);\n            var read = await Electron.Clipboard.ReadTextAsync();\n            read.Should().Be(text);\n        }\n\n        [IntegrationFact]\n        public async Task Available_formats_contains_text_after_write()\n        {\n            var text = \"FormatsTest\";\n            Electron.Clipboard.WriteText(text);\n            var formats = await Electron.Clipboard.AvailableFormatsAsync();\n            formats.Should().Contain(f => f.Contains(\"text\") || f.Contains(\"TEXT\") || f.Contains(\"plain\"));\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(MacOS)]\n        [SupportedOSPlatform(Windows)]\n        public async Task Bookmark_write_and_read()\n        {\n            var url = \"https://electron-test.com\";\n            Electron.Clipboard.WriteBookmark(\"TitleTest\", url);\n            var bookmark = await Electron.Clipboard.ReadBookmarkAsync();\n            bookmark.Url.Should().Be(url);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/CookiesTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.Common;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class CookiesTests : IntegrationTestBase\n    {\n        public CookiesTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact(Skip = \"Cookie set/get requires navigation to domain; skipping until test harness serves page\")]\n        public async Task Cookie_set_get_remove_sequence()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            var changed = false;\n            session.Cookies.OnChanged += (cookie, cause, removed) => changed = true;\n            // Navigate to example.com so cookie domain matches\n            await this.MainWindow.WebContents.LoadURLAsync(\"https://example.com\");\n            // Set via renderer for now\n            await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>(\"document.cookie='integration_cookie=1;path=/';\");\n            await Task.Delay(500.ms());\n            changed.Should().BeTrue();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/GlobalShortcutTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using System.Runtime.InteropServices;\n    using ElectronNET.API;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class GlobalShortcutTests : IntegrationTestBase\n    {\n        public GlobalShortcutTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Can_register_and_unregister()\n        {\n            var accel = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? \"Cmd+Alt+G\" : \"Ctrl+Alt+G\";\n            var tcs = new TaskCompletionSource<bool>();\n            Electron.GlobalShortcut.Register(accel, () => tcs.TrySetResult(true));\n            var isRegistered = await Electron.GlobalShortcut.IsRegisteredAsync(accel);\n            isRegistered.Should().BeTrue();\n            Electron.GlobalShortcut.Unregister(accel);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/HostHookTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class HostHookTests : IntegrationTestBase\n    {\n        public HostHookTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact(Skip = \"Requires HostHook setup; skipping\")]\n        public async Task HostHook_call_returns_value()\n        {\n            var result = await Electron.HostHook.CallAsync<string>(\"create-excel-file\", \".\");\n            result.Should().NotBeNull();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/IpcMainTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API;\n    using ElectronNET.Common;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class IpcMainTests : IntegrationTestBase\n    {\n        public IpcMainTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Ipc_On_receives_message_from_renderer()\n        {\n            object received = null;\n\n            var tcs = new TaskCompletionSource<string>();\n            await Electron.IpcMain.On(\"ipc-on-test\", obj =>\n            {\n                received = obj;\n                tcs.TrySetResult(obj as string);\n            });\n\n            await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>(\"require('electron').ipcRenderer.send('ipc-on-test','payload123')\");\n\n            var result = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5));\n\n            received.Should().BeOfType<string>();\n            received.Should().Be(\"payload123\");\n            result.Should().Be(\"payload123\");\n        }\n\n        [IntegrationFact]\n        public async Task Ipc_Once_only_fires_once()\n        {\n            var count = 0;\n            Electron.IpcMain.Once(\"ipc-once-test\", _ => count++);\n            await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>(\"const {ipcRenderer}=require('electron'); ipcRenderer.send('ipc-once-test','a'); ipcRenderer.send('ipc-once-test','b');\");\n            await Task.Delay(500.ms());\n            count.Should().Be(1);\n        }\n\n        [IntegrationFact]\n        public async Task Ipc_RemoveAllListeners_stops_receiving()\n        {\n            var fired = false;\n            await Electron.IpcMain.On(\"ipc-remove-test\", _ => fired = true);\n            Electron.IpcMain.RemoveAllListeners(\"ipc-remove-test\");\n            await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>(\"require('electron').ipcRenderer.send('ipc-remove-test','x')\");\n            await Task.Delay(400.ms());\n            fired.Should().BeFalse();\n        }\n\n        [IntegrationFact]\n        public async Task Ipc_OnSync_returns_value()\n        {\n            object received = null;\n\n            Electron.IpcMain.OnSync(\"ipc-sync-test\", (obj) =>\n            {\n                received = obj;\n                return \"pong\";\n            });\n            var ret = await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>(\"require('electron').ipcRenderer.sendSync('ipc-sync-test','ping')\");\n\n            received.Should().BeOfType<string>();\n            received.Should().Be(\"ping\");\n\n            ret.Should().Be(\"pong\");\n        }\n\n        [IntegrationFact]\n        public async Task Ipc_Send_from_main_reaches_renderer()\n        {\n            // Listener: store raw arg; if Electron packs differently we will normalize later\n            await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>(@\"(function(){ const {ipcRenderer}=require('electron'); ipcRenderer.once('main-to-render',(e,arg)=>{ globalThis.__mainToRender = arg;}); return 'ready'; })();\");\n            Electron.IpcMain.Send(this.MainWindow, \"main-to-render\", \"hello-msg\");\n            string value = \"\";\n            for (int i = 0; i < 20; i++)\n            {\n                var jsVal = await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>(\"globalThis.__mainToRender === undefined ? '' : (typeof globalThis.__mainToRender === 'string' ? globalThis.__mainToRender : JSON.stringify(globalThis.__mainToRender))\");\n                value = jsVal?.ToString() ?? \"\";\n                if (!string.IsNullOrEmpty(value))\n                {\n                    break;\n                }\n\n                await Task.Delay(100.ms());\n            }\n\n            // Normalize possible JSON array [\"hello-msg\"] case\n            if (value.StartsWith(\"[\\\"\") && value.EndsWith(\"\\\"]\"))\n            {\n                // Extract first element between [\" and \"]\n                value = value.Substring(2, value.Length - 4);\n            }\n\n            value.Should().Be(\"hello-msg\");\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/MenuTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n    using ElectronNET.Common;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class MenuTests : IntegrationTestBase\n    {\n        public MenuTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task ApplicationMenu_click_invokes_handler()\n        {\n            var clicked = false;\n            var items = new[]\n            {\n                new MenuItem\n                {\n                    Label = \"File\",\n                    Submenu = new[]\n                    {\n                        new MenuItem { Label = \"Ping\", Click = () => clicked = true },\n                    },\n                },\n            };\n            Electron.Menu.SetApplicationMenu(items);\n            var targetId = items[0].Submenu[0].Id;\n            await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>($\"require('electron').ipcRenderer.send('integration-click-application-menu','{targetId}')\");\n            for (int i = 0; i < 20 && !clicked; i++)\n            {\n                await Task.Delay(100.ms());\n            }\n\n            clicked.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task ContextMenu_popup_registers_items()\n        {\n            var win = this.MainWindow;\n            var ctxClicked = false;\n            var ctxItems = new[] { new MenuItem { Label = \"Ctx\", Click = () => ctxClicked = true } };\n            Electron.Menu.SetContextMenu(win, ctxItems);\n            var ctxId = ctxItems[0].Id;\n            // simulate popup then click\n            Electron.Menu.ContextMenuPopup(win);\n            await this.MainWindow.WebContents.ExecuteJavaScriptAsync<string>($\"require('electron').ipcRenderer.send('integration-click-context-menu',{win.Id},'{ctxId}')\");\n            for (int i = 0; i < 20 && !ctxClicked; i++)\n            {\n                await Task.Delay(100.ms());\n            }\n\n            ctxClicked.Should().BeTrue();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/MultiEventRegistrationTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class MultiEventRegistrationTests : IntegrationTestBase\n    {\n        public MultiEventRegistrationTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        private static async Task<bool> WaitAllOrTimeout(TimeSpan timeout, params Task[] tasks)\n        {\n            var all = Task.WhenAll(tasks);\n            var completed = await Task.WhenAny(all, Task.Delay(timeout));\n            return ReferenceEquals(completed, all) && all.IsCompletedSuccessfully;\n        }\n\n        [IntegrationFact]\n        public async Task BrowserWindow_OnResize_multiple_handlers_called()\n        {\n            var win = this.MainWindow;\n            var h1 = new TaskCompletionSource();\n            var h2 = new TaskCompletionSource();\n            var h3 = new TaskCompletionSource();\n\n            win.OnResize += () => h1.TrySetResult();\n            win.OnResize += () => h2.TrySetResult();\n            win.OnResize += () => h3.TrySetResult();\n\n            var size = await win.GetSizeAsync();\n            // trigger resize\n            win.SetSize(size[0] + 20, size[1] + 10);\n\n            var ok = await WaitAllOrTimeout(TimeSpan.FromSeconds(5), h1.Task, h2.Task, h3.Task);\n\n            if (!ok)\n            {\n                throw new Xunit.Sdk.XunitException($\"Not all events were fired: \\nEvent1 fired: {h1.Task.IsCompleted}\\nEvent2 fired: {h2.Task.IsCompleted}\\nEvent3 fired: {h3.Task.IsCompleted}\");\n            }\n        }\n\n        [IntegrationFact]\n        public async Task WebContents_OnDomReady_multiple_handlers_called()\n        {\n            var wc = this.MainWindow.WebContents;\n            var r1 = new TaskCompletionSource();\n            var r2 = new TaskCompletionSource();\n\n            wc.OnDomReady += () => r1.TrySetResult();\n            wc.OnDomReady += () => r2.TrySetResult();\n\n            await wc.LoadURLAsync(\"about:blank\");\n\n            var ok = await WaitAllOrTimeout(TimeSpan.FromSeconds(2), r1.Task, r2.Task);\n\n            if (!ok)\n            {\n                throw new Xunit.Sdk.XunitException($\"Not all events were fired: \\nEvent1 fired: {r1.Task.IsCompleted}\\nEvent2 fired: {r2.Task.IsCompleted}\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/NativeImageTests.cs",
    "content": "using System.Drawing;\nusing ElectronNET.API.Entities;\nusing ElectronNET.IntegrationTests.Common;\nusing System.Runtime.Versioning;\nusing RectangleEntity = ElectronNET.API.Entities.Rectangle;\n\nnamespace ElectronNET.IntegrationTests.Tests\n{\n    [Collection(\"ElectronCollection\")]\n    [SupportedOSPlatform(Windows)]\n    public class NativeImageTests : IntegrationTestBase\n    {\n        public NativeImageTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Create_from_bitmap_and_to_png()\n        {\n            using var bmp = new Bitmap(10, 10);\n            using (var g = Graphics.FromImage(bmp))\n            {\n                g.Clear(Color.Red);\n            }\n\n            var native = NativeImage.CreateFromBitmap(bmp);\n            var size = native.GetSize();\n            size.Width.Should().Be(10);\n            size.Height.Should().Be(10);\n            var png = native.ToPNG(new ToPNGOptions { ScaleFactor = 1.0f });\n            png.Should().NotBeNull();\n            png!.Length.Should().BeGreaterThan(0);\n        }\n\n        [IntegrationFact]\n        public async Task Create_from_buffer_and_to_data_url()\n        {\n            // Prepare PNG bytes\n            using var bmp = new Bitmap(8, 8);\n            using (var g = Graphics.FromImage(bmp))\n            {\n                g.Clear(Color.Blue);\n            }\n\n            using var ms = new MemoryStream();\n            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);\n            var bytes = ms.ToArray();\n            var native = NativeImage.CreateFromBuffer(bytes);\n            var dataUrl = native.ToDataURL(new ToDataUrlOptions { ScaleFactor = 1.0f });\n            dataUrl.Should().NotBeNullOrWhiteSpace();\n            dataUrl!.StartsWith(\"data:image/\", StringComparison.Ordinal).Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task Resize_and_crop_produce_expected_sizes()\n        {\n            using var bmp = new Bitmap(12, 10);\n            using (var g = Graphics.FromImage(bmp))\n            {\n                g.Clear(Color.Green);\n            }\n\n            var native = NativeImage.CreateFromBitmap(bmp);\n            var resized = native.Resize(new ResizeOptions { Width = 6, Height = 5 });\n            var rsize = resized.GetSize();\n            rsize.Width.Should().Be(6);\n            rsize.Height.Should().Be(5);\n            var cropped = native.Crop(new RectangleEntity { X = 2, Y = 2, Width = 4, Height = 3 });\n            var csize = cropped.GetSize();\n            csize.Width.Should().Be(4);\n            csize.Height.Should().Be(3);\n        }\n\n        [IntegrationFact]\n        public async Task Add_representation_for_scale_factor()\n        {\n            using var bmp = new Bitmap(5, 5);\n            using (var g = Graphics.FromImage(bmp))\n            {\n                g.Clear(Color.Black);\n            }\n\n            using var ms = new MemoryStream();\n            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);\n            var buffer = ms.ToArray();\n            var native = NativeImage.CreateFromBitmap(bmp);\n            native.AddRepresentation(new AddRepresentationOptions { Buffer = buffer, ScaleFactor = 2.0f });\n            var size2X = native.GetSize(2.0f);\n            size2X.Should().NotBeNull();\n            size2X.Width.Should().Be(5);\n            size2X.Height.Should().Be(5);\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/NativeThemeTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using System.Runtime.Versioning;\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n    using ElectronNET.Common;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class NativeThemeTests : IntegrationTestBase\n    {\n        public NativeThemeTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task ThemeSource_roundtrip()\n        {\n            // Capture initial\n            _ = await Electron.NativeTheme.ShouldUseDarkColorsAsync();\n            // Force light\n            await Task.Delay(50.ms());\n            Electron.NativeTheme.SetThemeSource(ThemeSourceMode.Light);\n            await Task.Delay(500.ms());\n            var useDarkAfterLight = await Electron.NativeTheme.ShouldUseDarkColorsAsync();\n            var themeSourceLight = await Electron.NativeTheme.GetThemeSourceAsync();\n            // Force dark\n            Electron.NativeTheme.SetThemeSource(ThemeSourceMode.Dark);\n            await Task.Delay(500.ms());\n            var useDarkAfterDark = await Electron.NativeTheme.ShouldUseDarkColorsAsync();\n            var themeSourceDark = await Electron.NativeTheme.GetThemeSourceAsync();\n            // Restore system\n            Electron.NativeTheme.SetThemeSource(ThemeSourceMode.System);\n            await Task.Delay(500.ms());\n            var themeSourceSystem = await Electron.NativeTheme.GetThemeSourceAsync();\n            // Assertions are tolerant (platform dependent)\n            useDarkAfterLight.Should().BeFalse(\"forcing Light should result in light colors\");\n            useDarkAfterDark.Should().BeTrue(\"forcing Dark should result in dark colors\");\n            themeSourceLight.Should().Be(ThemeSourceMode.Light);\n            themeSourceDark.Should().Be(ThemeSourceMode.Dark);\n            themeSourceSystem.Should().Be(ThemeSourceMode.System);\n        }\n\n        [IntegrationFact]\n        public async Task Updated_event_fires_on_change()\n        {\n            var fired = false;\n            Electron.NativeTheme.Updated += () => fired = true;\n            Electron.NativeTheme.SetThemeSource(ThemeSourceMode.Dark);\n            await Task.Delay(400.ms());\n            Electron.NativeTheme.SetThemeSource(ThemeSourceMode.Light);\n            for (int i = 0; i < 10 && !fired; i++)\n            {\n                await Task.Delay(100.ms());\n            }\n\n            fired.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(MacOS)]\n        [SupportedOSPlatform(Windows)]\n        public async Task Should_use_high_contrast_colors_check()\n        {\n            var metrics = await Electron.NativeTheme.ShouldUseHighContrastColorsAsync();\n            metrics.Should().Be(false);\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(MacOS)]\n        [SupportedOSPlatform(Windows)]\n        public async Task Should_use_inverted_colors_check()\n        {\n            var metrics = await Electron.NativeTheme.ShouldUseInvertedColorSchemeAsync();\n            metrics.Should().Be(false);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/NotificationTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using System.Runtime.InteropServices;\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n    using ElectronNET.Common;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class NotificationTests : IntegrationTestBase\n    {\n        public NotificationTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Notification_create_check()\n        {\n            Skip.If(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), \"Always returns false. Might need full-blown desktop environment\");\n\n            var tcs = new TaskCompletionSource();\n\n            var options = new NotificationOptions(\"Notification Title\", \"Notification test 123\");\n            options.OnShow = () => tcs.SetResult();\n\n            await Task.Delay(500.ms());\n\n            Electron.Notification.Show(options);\n\n            await Task.WhenAny(tcs.Task, Task.Delay(5.seconds()));\n\n            tcs.Task.IsCompletedSuccessfully.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task Notification_is_supported_check()\n        {\n            Skip.If(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), \"Always returns false. Might need full-blown desktop environment\");\n\n            var supported = await Electron.Notification.IsSupportedAsync();\n            supported.Should().BeTrue();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/ProcessTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class ProcessTests : IntegrationTestBase\n    {\n        public ProcessTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Process_info_is_accessible()\n        {\n            // Use renderer to fetch process info and round-trip\n            var execPath = await Electron.WindowManager.CreateWindowAsync(new API.Entities.BrowserWindowOptions { Show = false }, \"about:blank\");\n            var result = await execPath.WebContents.ExecuteJavaScriptAsync<string>(\"process.execPath && process.platform ? 'ok' : 'fail'\");\n            result.Should().Be(\"ok\");\n        }\n\n        [IntegrationFact]\n        public async Task Process_properties_are_populated()\n        {\n            var execPath = await Electron.Process.ExecPathAsync;\n            execPath.Should().NotBeNullOrWhiteSpace();\n\n            var pid = await Electron.Process.PidAsync;\n            pid.Should().BeGreaterThan(0);\n\n            var platform = await Electron.Process.PlatformAsync;\n            platform.Should().NotBeNullOrWhiteSpace();\n\n            var argv = await Electron.Process.ArgvAsync;\n            argv.Should().NotBeNull();\n            argv.Length.Should().BeGreaterThan(0);\n\n            var type = await Electron.Process.TypeAsync;\n            type.Should().NotBeNullOrWhiteSpace();\n\n            var version = await Electron.Process.VersionsAsync;\n            version.Should().NotBeNull();\n            version.Chrome.Should().NotBeNullOrWhiteSpace();\n            version.Electron.Should().NotBeNullOrWhiteSpace();\n\n            var defaultApp = await Electron.Process.DefaultAppAsync;\n            defaultApp.Should().BeTrue();\n\n            var isMainFrame = await Electron.Process.IsMainFrameAsync;\n            isMainFrame.Should().BeFalse();\n\n            var resourcePath = await Electron.Process.ResourcesPathAsync;\n            resourcePath.Should().NotBeNullOrWhiteSpace();\n\n            var upTime = await Electron.Process.UpTimeAsync;\n            upTime.Should().BeGreaterThan(0);\n\n            var arch = await Electron.Process.ArchAsync;\n            arch.Should().NotBeNullOrWhiteSpace();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/ScreenTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using System.Runtime.Versioning;\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class ScreenTests : IntegrationTestBase\n    {\n        public ScreenTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact(SkipOnWsl = true)]\n        public async Task Primary_display_has_positive_dimensions()\n        {\n            var display = await Electron.Screen.GetPrimaryDisplayAsync();\n            display.Size.Width.Should().BeGreaterThan(0);\n            display.Size.Height.Should().BeGreaterThan(0);\n        }\n\n        [IntegrationFact(SkipOnWsl = true)]\n        public async Task GetAllDisplays_returns_at_least_one()\n        {\n            var displays = await Electron.Screen.GetAllDisplaysAsync();\n            displays.Should().NotBeNull();\n            displays.Length.Should().BeGreaterThan(0);\n        }\n\n        [IntegrationFact]\n        public async Task GetCursorScreenPoint_check()\n        {\n            var point = await Electron.Screen.GetCursorScreenPointAsync();\n            point.Should().NotBeNull();\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(MacOS)]\n        public async Task GetMenuBarWorkArea_check()\n        {\n            var area = await Electron.Screen.GetMenuBarWorkAreaAsync();\n            area.Should().NotBeNull();\n            area.X.Should().BeGreaterThanOrEqualTo(0);\n            area.Y.Should().BeGreaterThanOrEqualTo(0);\n            area.Height.Should().BeGreaterThan(0);\n            area.Width.Should().BeGreaterThan(0);\n        }\n\n        [IntegrationFact(SkipOnWsl = true)]\n        public async Task GetDisplayNearestPoint_check()\n        {\n            var point = new Point\n            {\n                X = 100,\n                Y = 100\n            };\n            var display = await Electron.Screen.GetDisplayNearestPointAsync(point);\n            display.Should().NotBeNull();\n            display.Size.Width.Should().BeGreaterThan(0);\n            display.Size.Height.Should().BeGreaterThan(0);\n        }\n\n        [IntegrationFact(SkipOnWsl = true)]\n        public async Task GetDisplayMatching_check()\n        {\n            var rectangle = new Rectangle\n            {\n                X = 100,\n                Y = 100,\n                Width = 100,\n                Height = 100\n            };\n            var display = await Electron.Screen.GetDisplayMatchingAsync(rectangle);\n            display.Should().NotBeNull();\n            display.Size.Width.Should().BeGreaterThan(0);\n            display.Size.Height.Should().BeGreaterThan(0);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/SessionTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API.Entities;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class SessionTests : IntegrationTestBase\n    {\n        public SessionTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Session_preloads_roundtrip()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            _ = await session.GetPreloadsAsync();\n            // Use a dummy path; API should store value\n            session.SetPreloads(new[] { \"/tmp/preload_dummy.js\" });\n            var preloadsAfter = await session.GetPreloadsAsync();\n            preloadsAfter.Should().Contain(\"/tmp/preload_dummy.js\");\n        }\n\n        [IntegrationFact]\n        public async Task Session_proxy_set_and_resolve()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            // Provide all ctor args (pacScript empty to ignore, proxyRules direct, bypass empty)\n            await session.SetProxyAsync(new ProxyConfig(\"\", \"direct://\", \"\"));\n            var proxy = await session.ResolveProxyAsync(\"https://example.com\");\n            proxy.Should().NotBeNull();\n        }\n\n\n        [IntegrationFact]\n        public async Task Session_clear_cache_and_storage_completes()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            await session.ClearCacheAsync();\n            await session.ClearStorageDataAsync();\n            await session.ClearHostResolverCacheAsync();\n            // Ensure still can query user agent after clears\n            var ua = await session.GetUserAgent();\n            ua.Should().NotBeNullOrWhiteSpace();\n        }\n\n        [IntegrationFact]\n        public async Task Session_preloads_set_multiple_and_clear()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            session.SetPreloads(new[] { \"/tmp/a.js\", \"/tmp/b.js\" });\n            var after = await session.GetPreloadsAsync();\n            after.Should().Contain(\"/tmp/a.js\").And.Contain(\"/tmp/b.js\");\n            // Reset to empty\n            session.SetPreloads(Array.Empty<string>());\n            var empty = await session.GetPreloadsAsync();\n            empty.Should().NotContain(\"/tmp/a.js\");\n        }\n\n        [IntegrationFact]\n        public async Task Clear_auth_cache_overloads()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            await session.ClearAuthCacheAsync();\n            await session.ClearAuthCacheAsync(new RemovePassword(\"password\") { Origin = \"https://example.com\", Username = \"user\", Password = \"pw\", Realm = \"realm\", Scheme = Scheme.basic });\n        }\n\n        [IntegrationFact]\n        public async Task Clear_storage_with_options()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            await session.ClearStorageDataAsync(new ClearStorageDataOptions { Storages = new[] { \"cookies\" }, Quotas = new[] { \"temporary\" } });\n        }\n\n        [IntegrationFact]\n        public async Task Enable_disable_network_emulation()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            session.EnableNetworkEmulation(new EnableNetworkEmulationOptions { Offline = false, Latency = 10, DownloadThroughput = 50000, UploadThroughput = 20000 });\n            session.DisableNetworkEmulation();\n        }\n\n        [IntegrationFact]\n        public async Task Flush_storage_data_does_not_throw()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            session.FlushStorageData();\n        }\n\n        [IntegrationFact]\n        public async Task Set_user_agent_affects_new_navigation()\n        {\n            var session = this.MainWindow.WebContents.Session;\n            // Set UA and verify via session API (navigator.userAgent on existing WebContents may not reflect the override)\n            session.SetUserAgent(\"IntegrationAgent/1.0\");\n            var ua = await session.GetUserAgent();\n            ua.Should().NotBeNullOrWhiteSpace();\n            ua.Should().Contain(\"IntegrationAgent/1.0\");\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/ShellTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class ShellTests : IntegrationTestBase\n    {\n        public ShellTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact(Skip = \"This can keep the test process hanging until the e-mail window is closed\")]\n        public async Task OpenExternal_invalid_scheme_returns_error_or_empty()\n        {\n            var error = await Electron.Shell.OpenExternalAsync(\"mailto:test@example.com\");\n            (error == string.Empty || error.Contains(\"@\") || error.Length > 0).Should().BeTrue(); // call succeeded\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/ThumbarButtonTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using System.Runtime.Versioning;\n    using ElectronNET.API.Entities;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class ThumbarButtonTests : IntegrationTestBase\n    {\n        public ThumbarButtonTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(Windows)]\n        public async Task SetThumbarButtons_returns_success()\n        {\n            var btn = new ThumbarButton(\"icon.png\") { Tooltip = \"Test\" };\n            var success = await this.MainWindow.SetThumbarButtonsAsync(new[] { btn });\n            success.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        [SupportedOSPlatform(Windows)]\n        public async Task Thumbar_button_click_invokes_callback()\n        {\n            var icon = Path.Combine(Directory.GetCurrentDirectory(), \"ElectronNET.WebApp\", \"wwwroot\", \"icon.png\");\n            if (!File.Exists(icon))\n            {\n                return; // skip if icon missing\n            }\n\n            var tcs = new TaskCompletionSource<bool>();\n            var btn = new ThumbarButton(icon) { Tooltip = \"Test\", Flags = new[] { ThumbarButtonFlag.enabled }, Click = () => tcs.TrySetResult(true) };\n            var ok = await this.MainWindow.SetThumbarButtonsAsync(new[] { btn });\n            ok.Should().BeTrue();\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/TrayTests.cs",
    "content": "namespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class TrayTests : IntegrationTestBase\n    {\n        public TrayTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Can_create_tray_and_destroy()\n        {\n            //await Electron.Tray.Show(\"assets/icon.png\");\n            await Electron.Tray.Show(null);\n            var isDestroyed = await Electron.Tray.IsDestroyedAsync();\n            isDestroyed.Should().BeFalse();\n            await Electron.Tray.Destroy();\n            (await Electron.Tray.IsDestroyedAsync()).Should().BeTrue();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/Tests/WebContentsTests.cs",
    "content": "using System.Runtime.InteropServices;\n\nnamespace ElectronNET.IntegrationTests.Tests\n{\n    using ElectronNET.API;\n    using ElectronNET.API.Entities;\n    using ElectronNET.Common;\n    using ElectronNET.IntegrationTests.Common;\n\n    [Collection(\"ElectronCollection\")]\n    public class WebContentsTests : IntegrationTestBase\n    {\n        public WebContentsTests(ElectronFixture fx) : base(fx)\n        {\n        }\n\n        [IntegrationFact]\n        public async Task Can_get_url_after_navigation()\n        {\n            var wc = this.MainWindow.WebContents;\n            await wc.LoadURLAsync(\"https://example.com\");\n            var url = await wc.GetUrl();\n            url.Should().Contain(\"example.com\");\n        }\n\n        [IntegrationFact]\n        public async Task ExecuteJavaScript_returns_title()\n        {\n            var wc = this.MainWindow.WebContents;\n            await wc.LoadURLAsync(\"https://example.com\");\n            var title = await wc.ExecuteJavaScriptAsync<string>(\"document.title\");\n            title.Should().NotBeNull();\n        }\n\n        [IntegrationFact]\n        public async Task DomReady_event_fires()\n        {\n            var wc = this.MainWindow.WebContents;\n            var fired = false;\n            wc.OnDomReady += () => fired = true;\n            await wc.LoadURLAsync(\"https://example.com\");\n            await Task.Delay(500.ms());\n            fired.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task Can_print_to_pdf()\n        {\n            var html = \"data:text/html,<html><body><h1>PDF Test</h1><p>Electron.NET</p></body></html>\";\n            await this.MainWindow.WebContents.LoadURLAsync(html);\n            var tmp = Path.Combine(Path.GetTempPath(), $\"electronnet_pdf_{Guid.NewGuid():N}.pdf\");\n            try\n            {\n                var ok = await this.MainWindow.WebContents.PrintToPDFAsync(tmp);\n                ok.Should().BeTrue();\n                File.Exists(tmp).Should().BeTrue();\n                new FileInfo(tmp).Length.Should().BeGreaterThan(0);\n            }\n            finally\n            {\n                if (File.Exists(tmp))\n                {\n                    File.Delete(tmp);\n                }\n            }\n        }\n\n        [IntegrationFact]\n        public async Task Can_basic_print()\n        {\n            var html = \"data:text/html,<html><body><h2>Print Test</h2></body></html>\";\n            await this.MainWindow.WebContents.LoadURLAsync(html);\n            var ok = await this.MainWindow.WebContents.PrintAsync(new PrintOptions { Silent = true, PrintBackground = true });\n            ok.Should().BeTrue();\n        }\n\n        [IntegrationFact]\n        public async Task GetPrintersAsync_check()\n        {\n            var info = await this.MainWindow.WebContents.GetPrintersAsync();\n            info.Should().NotBeNull();\n        }\n\n        [IntegrationFact]\n        public async Task GetSetZoomFactor_check()\n        {\n            await this.MainWindow.WebContents.GetZoomFactorAsync();\n            var ok = await this.MainWindow.WebContents.GetZoomFactorAsync();\n            ok.Should().BeGreaterThan(0.0);\n            this.MainWindow.WebContents.SetZoomFactor(2.0);\n            await Task.Delay(500.ms());\n            ok = await this.MainWindow.WebContents.GetZoomFactorAsync();\n            ok.Should().Be(2.0);\n        }\n\n        [IntegrationFact]\n        public async Task GetSetZoomLevel_check()\n        {\n            BrowserWindow window = null;\n\n            try\n            {\n                window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, \"about:blank\");\n\n                await Task.Delay(100.ms());\n\n                window.WebContents.SetZoomLevel(0);\n                await Task.Delay(500.ms());\n\n                var ok = await window.WebContents.GetZoomLevelAsync();\n                ok.Should().Be(0);\n\n                window.WebContents.SetZoomLevel(2);\n                await Task.Delay(500.ms());\n\n                ok = await window.WebContents.GetZoomLevelAsync();\n                ok.Should().Be(2);\n            }\n            finally\n            {\n                window?.Destroy();\n            }\n        }\n\n        [IntegrationFact]\n        public async Task DevTools_check()\n        {\n            BrowserWindow window = null;\n\n            try\n            {\n                window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, \"about:blank\");\n\n                await Task.Delay(3.seconds());\n\n                window.WebContents.IsDevToolsOpened().Should().BeFalse();\n                window.WebContents.OpenDevTools();\n                await Task.Delay(5.seconds());\n\n                window.WebContents.IsDevToolsOpened().Should().BeTrue();\n                window.WebContents.CloseDevTools();\n                await Task.Delay(2.seconds());\n\n                window.WebContents.IsDevToolsOpened().Should().BeFalse();\n            }\n            finally\n            {\n                window?.Destroy();\n            }\n        }\n\n        [IntegrationFact]\n        public async Task GetSetAudioMuted_check()\n        {\n            this.MainWindow.WebContents.SetAudioMuted(true);\n            await Task.Delay(500.ms());\n            var ok = await this.MainWindow.WebContents.IsAudioMutedAsync();\n            ok.Should().BeTrue();\n            this.MainWindow.WebContents.SetAudioMuted(false);\n            await Task.Delay(500.ms());\n            ok = await this.MainWindow.WebContents.IsAudioMutedAsync();\n            ok.Should().BeFalse();\n\n            // Assuming no audio is playing, IsCurrentlyAudibleAsync should return false\n            // there is no way to play audio in this test\n            ok = await this.MainWindow.WebContents.IsCurrentlyAudibleAsync();\n            ok.Should().BeFalse();\n        }\n\n        [IntegrationFact]\n        public async Task GetSetUserAgent_check()\n        {\n            BrowserWindow window = null;\n\n            try\n            {\n                await Task.Delay(1.seconds());\n\n                window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, \"about:blank\");\n\n                await Task.Delay(5.seconds());\n\n                window.WebContents.SetUserAgent(\"MyUserAgent/1.0\");\n\n                await Task.Delay(2.seconds());\n\n                var ok = await window.WebContents.GetUserAgentAsync();\n                ok.Should().Be(\"MyUserAgent/1.0\");\n            }\n            finally\n            {\n                window?.Destroy();\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "src/ElectronNET.IntegrationTests/xunit.runner.json",
    "content": "{\n  \"$schema\": \"https://xunit.net/schema/current/xunit.runner.schema.json\",\n  \"methodDisplay\": \"method\",\n  \"diagnosticMessages\": true,\n  \"parallelizeTestCollections\": false,\n  \"longRunningTestSeconds\": 60\n}\n"
  },
  {
    "path": "src/ElectronNET.Lean.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.12.35707.178\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ElectronNET.API\", \"ElectronNET.API\\ElectronNET.API.csproj\", \"{A78157BA-B754-45F1-969F-D6A513CA0E72}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ElectronNET.Build\", \"ElectronNET.Build\\ElectronNET.Build.csproj\", \"{829FC339-4785-4229-ABA5-53ADB544DA00}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ElectronNET\", \"ElectronNET\\ElectronNET.csproj\", \"{8860606D-6847-F22A-5AED-DF4E0984DD24}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00} = {829FC339-4785-4229-ABA5-53ADB544DA00}\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"!Config\", \"!Config\", \"{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t..\\Changelog.md = ..\\Changelog.md\n\t\tcommon.props = common.props\n\t\tglobal.json = global.json\n\t\t..\\NuGet.config = ..\\NuGet.config\n\tEndProjectSection\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ElectronNET.AspNet\", \"ElectronNET.AspNet\\ElectronNET.AspNet.csproj\", \"{DD10D21A-D131-1D9C-33F9-406046E0C5B0}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Core\", \"Core\", \"{1BB6F634-2831-4496-83A6-BC6761DCEC8D}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D}\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D}\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D}\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {81A62E71-9E04-4EFE-AD5C-23165375F8EF}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/Controllers/HomeController.cs",
    "content": "using ElectronNET.API;\nusing Microsoft.AspNetCore.Mvc;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.Samples.ElectronHostHook.Controllers\n{\n    public class HomeController : Controller\n    {\n        public async Task<IActionResult> Index()\n        {\n            string message = \"Electron not active\";\n            if (HybridSupport.IsElectronActive)\n            {\n                // Call the HostHook defined in ElectronHostHook/index.ts\n                var result = await Electron.HostHook.CallAsync<string>(\"ping\", \"Hello from C#\");\n                message = $\"Sent 'Hello from C#', Received: '{result}'\";\n            }\n\n            return View(\"Index\", message);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/.gitignore",
    "content": "node_modules\n*.js\n*.js.map\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/connector.ts",
    "content": "import { Socket } from \"socket.io\";\n\nexport class Connector {\n    constructor(private socket: Socket, public app: any) {\n    }\n\n    on(key: string, javaScriptCode: Function): void {\n        this.socket.on(key, (...args: any[]) => {\n            const id: string = args.pop();\n            try {\n                javaScriptCode(...args, (data) => {\n                    if (data) {\n                        this.socket.emit(`${key}Complete${id}`, data);\n                    }\n                });\n            } catch (error) {\n                this.socket.emit(`${key}Error${id}`, `Host Hook Exception`, error);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/index.ts",
    "content": "import { Connector } from \"./connector\";\nimport { Socket } from \"socket.io\";\n\nexport class HookService extends Connector {\n    constructor(socket: Socket, public app: any) {\n        super(socket, app);\n    }\n\n    onHostReady(): void {\n        // execute your own JavaScript Host logic here\n        this.on(\"ping\", (msg, done) => {\n            console.log(\"Received ping from C#:\", msg);\n            done(\"pong: \" + msg);\n        });\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/package.json",
    "content": "{\n  \"name\": \"electron-host-hook\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Connector for Electron.NET projects.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"socket.io\": \"^4.8.1\"\n  },\n  \"devDependencies\": {\n    \"typescript\": \"^5.9.3\"\n  }\n}\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"ES2019\",\n    \"sourceMap\": true,\n    \"skipLibCheck\": true\n  },\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/ElectronNET.Samples.ElectronHostHook.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <ElectronNetDevMode>true</ElectronNetDevMode>\n  </PropertyGroup>\n\n  <Import Project=\"..\\ElectronNET\\build\\ElectronNET.Core.props\" Condition=\"$(ElectronNetDevMode)\" />\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>\n    <AspNetCoreModuleName>AspNetCoreModule</AspNetCoreModuleName>\n    <IsPackable>false</IsPackable>\n    <TypeScriptModuleKind>commonjs</TypeScriptModuleKind>\n    <TypeScriptUseNodeJS>true</TypeScriptUseNodeJS>\n    <TypeScriptTSConfig>ElectronHostHook/tsconfig.json</TypeScriptTSConfig>\n    <TypeScriptCompileOnSaveEnabled>true</TypeScriptCompileOnSaveEnabled>\n    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <TypeScriptCompile Remove=\"**\\node_modules\\**\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ElectronNET.API\\ElectronNET.API.csproj\" Condition=\"$(ElectronNetDevMode)\" />\n    <ProjectReference Include=\"..\\ElectronNET.AspNet\\ElectronNET.AspNet.csproj\" Condition=\"$(ElectronNetDevMode)\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"ElectronNET.Core\" Version=\"0.4.1\" Condition=\"'$(ElectronNetDevMode)' != 'true'\" />\n    <PackageReference Include=\"ElectronNET.Core.AspNet\" Version=\"0.4.1\" Condition=\"'$(ElectronNetDevMode)' != 'true'\" />\n    <PackageReference Include=\"Microsoft.TypeScript.MSBuild\" Version=\"5.9.3\" />\n  </ItemGroup>\n\n  <Import Project=\"..\\ElectronNET\\build\\ElectronNET.Core.targets\" Condition=\"$(ElectronNetDevMode)\" />\n</Project>\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/Program.cs",
    "content": "using ElectronNET.API;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace ElectronNET.Samples.ElectronHostHook\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            var builder = WebApplication.CreateBuilder(args);\n\n            builder.WebHost.UseElectron(args, async () =>\n            {\n                var window = await Electron.WindowManager.CreateWindowAsync();\n            });\n\n            builder.Services.AddElectron();\n            builder.Services.AddControllersWithViews();\n\n            var app = builder.Build();\n\n            app.UseStaticFiles();\n            app.UseRouting();\n\n            app.MapControllerRoute(\n                name: \"default\",\n                pattern: \"{controller=Home}/{action=Index}/{id?}\");\n\n            app.Run();\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/Properties/electron-builder.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/electron-userland/electron-builder/refs/heads/master/packages/app-builder-lib/scheme.json\",\n  \"compression\": \"maximum\",\n  \"linux\": {\n    \"target\": [\n      \"tar.xz\"\n    ],\n    \"executableArgs\": [ \"--no-sandbox\" ],\n    \"artifactName\": \"${name}-${arch}-${version}.${ext}\"\n  },\n  \"win\": {\n    \"target\": [\n      {\n        \"target\": \"portable\",\n        \"arch\": \"x64\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"ElectronNET.Samples.ElectronHostHook\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": false,\n      \"applicationUrl\": \"http://localhost:5000\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/ElectronNET.Samples.ElectronHostHook/Views/Home/Index.cshtml",
    "content": "@model string\n@{\n    Layout = null;\n}\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>ElectronHostHook Sample</title>\n    <style>\n        body { font-family: sans-serif; padding: 20px; }\n        .result { padding: 10px; background-color: #f0f0f0; border: 1px solid #ccc; margin-top: 10px; }\n    </style>\n</head>\n<body>\n    <h1>ElectronHostHook Sample</h1>\n    <p>This sample demonstrates bidirectional communication between C# and the Electron Host process.</p>\n    \n    <div class=\"result\">\n        <strong>Result:</strong> @Model\n    </div>\n</body>\n</html>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/AboutController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class AboutController : Controller\n    {\n        public IActionResult Index()\n        {\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/AppSysInformationController.cs",
    "content": "﻿using System.Linq;\nusing Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class AppSysInformationController : Controller\n    {\n        public IActionResult Index()\n        {\n            if(HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"app-info\", async (args) =>\n                {\n                    string appPath = await Electron.App.GetAppPathAsync();\n\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    Electron.IpcMain.Send(mainWindow, \"got-app-path\", appPath);\n                });\n\n                Electron.IpcMain.On(\"sys-info\", async (args) =>\n                {\n                    string homePath = await Electron.App.GetPathAsync(PathName.Home);\n\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    Electron.IpcMain.Send(mainWindow, \"got-sys-info\", homePath);\n                });\n\n                Electron.IpcMain.On(\"screen-info\", async (args) =>\n                {\n                    var display = await Electron.Screen.GetPrimaryDisplayAsync();\n\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    Electron.IpcMain.Send(mainWindow, \"got-screen-info\", display.Size);\n                });\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/ClipboardController.cs",
    "content": "using System;\nusing System.Drawing;\nusing System.IO;\nusing Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing System.Linq;\nusing ElectronNET.API.Entities;\nusing System.Text.Json;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class ClipboardController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"copy-to\", (text) =>\n                {\n                    Electron.Clipboard.WriteText(text.ToString());\n                });\n\n                Electron.IpcMain.On(\"paste-to\", async (text) =>\n                {\n                    Electron.Clipboard.WriteText(text.ToString());\n                    string pasteText = await Electron.Clipboard.ReadTextAsync();\n\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    Electron.IpcMain.Send(mainWindow, \"paste-from\", pasteText);\n                });\n\n                Electron.IpcMain.On(\"copy-image-to\",  (test) =>\n                {\n                    var nativeImage = NativeImage.CreateFromDataURL(test.ToString());\n                    Electron.Clipboard.WriteImage(nativeImage);\n                });\n\n                Electron.IpcMain.On(\"paste-image-to\", async test =>\n                {\n                    var nativeImage = await Electron.Clipboard.ReadImageAsync();\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    Electron.IpcMain.Send(mainWindow, \"paste-image-from\", JsonSerializer.Serialize(nativeImage));\n                });\n            }\n\n            return View();\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/CrashHangController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class CrashHangController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"process-crash\", async (args) =>\n                {\n                    string viewPath = $\"http://localhost:{ElectronNetRuntime.AspNetWebPort}/crashhang/processcrash\";\n\n                    var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);\n                    browserWindow.WebContents.OnCrashed += async (killed) =>\n                    {\n                        var options = new MessageBoxOptions(\"This process has crashed.\")\n                        {\n                            Type = MessageBoxType.info,\n                            Title = \"Renderer Process Crashed\",\n                            Buttons = new string[] { \"Reload\", \"Close\" }\n                        };\n                        var result = await Electron.Dialog.ShowMessageBoxAsync(options);\n\n                        if (result.Response == 0)\n                        {\n                            browserWindow.Reload();\n                        }\n                        else\n                        {\n                            browserWindow.Close();\n                        }\n                    };\n                });\n\n                Electron.IpcMain.On(\"process-hang\", async (args) =>\n                {\n                    string viewPath = $\"http://localhost:{ElectronNetRuntime.AspNetWebPort}/crashhang/processhang\";\n\n                    var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);\n                    browserWindow.OnUnresponsive += async () =>\n                    {\n                        var options = new MessageBoxOptions(\"This process is hanging.\")\n                        {\n                            Type = MessageBoxType.info,\n                            Title = \"Renderer Process Hanging\",\n                            Buttons = new string[] { \"Reload\", \"Close\" }\n                        };\n                        var result = await Electron.Dialog.ShowMessageBoxAsync(options);\n\n                        if (result.Response == 0)\n                        {\n                            browserWindow.Reload();\n                        }\n                        else\n                        {\n                            browserWindow.Close();\n                        }\n                    };\n                });\n            }\n\n            return View();\n        }\n\n        public IActionResult ProcessCrash()\n        {\n            return View();\n        }\n\n        public IActionResult ProcessHang()\n        {\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/DesktopCapturerController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class DesktopCapturerController : Controller\n    {\n        public IActionResult Index()\n        {\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/DialogsController.cs",
    "content": "﻿using System.Linq;\nusing Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class DialogsController : Controller\n    {\n        public IActionResult Index()\n        {\n            if(HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"select-directory\", async (args) => {\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    var options = new OpenDialogOptions\n                    {\n                        Properties = new OpenDialogProperty[] {\n                        OpenDialogProperty.openFile,\n                        OpenDialogProperty.openDirectory\n                    }\n                    };\n\n                    string[] files = await Electron.Dialog.ShowOpenDialogAsync(mainWindow, options);\n                    Electron.IpcMain.Send(mainWindow, \"select-directory-reply\", files);\n                });\n\n                Electron.IpcMain.On(\"error-dialog\", (args) =>\n                {\n                    Electron.Dialog.ShowErrorBox(\"An Error Message\", \"Demonstrating a really great message.\");\n                });\n\n                Electron.IpcMain.On(\"information-dialog\", async (args) =>\n                {\n                    var options = new MessageBoxOptions(\"This is an information dialog. Isn't it nice?\")\n                    {\n                        Type = MessageBoxType.info,\n                        Title = \"Information\",\n                        Buttons = new string[] { \"Yes\", \"No\" }\n                    };\n\n                    var result = await Electron.Dialog.ShowMessageBoxAsync(options);\n\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    Electron.IpcMain.Send(mainWindow, \"information-dialog-reply\", result.Response);\n                });\n\n                Electron.IpcMain.On(\"save-dialog\", async (args) =>\n                {\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    var options = new SaveDialogOptions\n                    {\n                        Title = \"Save an Image\",\n                        Filters = new FileFilter[]\n                        {\n                        new FileFilter { Name = \"Images\", Extensions = new string[] {\"jpg\", \"png\", \"gif\" } }\n                        }\n                    };\n\n                    var result = await Electron.Dialog.ShowSaveDialogAsync(mainWindow, options);\n                    Electron.IpcMain.Send(mainWindow, \"save-dialog-reply\", result);\n                });\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/HomeController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing System;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class HomeController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                if (OperatingSystem.IsMacOS() || OperatingSystem.IsWindows())\n                {\n                    Electron.PowerMonitor.OnLockScreen += () => { Console.WriteLine(\"Screen Locked detected from C#\"); };\n\n                    Electron.PowerMonitor.OnUnLockScreen += () => { Console.WriteLine(\"Screen unlocked detected from C# \"); };\n\n                    Electron.PowerMonitor.OnSuspend += () => { Console.WriteLine(\"The system is going to sleep\"); };\n\n                    Electron.PowerMonitor.OnResume += () => { Console.WriteLine(\"The system is resuming\"); };\n\n                    Electron.PowerMonitor.OnAC += () => { Console.WriteLine(\"The system changes to AC power\"); };\n\n                    Electron.PowerMonitor.OnBattery += () => { Console.WriteLine(\"The system is about to change to battery power\"); };\n                }\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/HostHookController.cs",
    "content": "﻿using ElectronNET.API;\nusing ElectronNET.API.Entities;\nusing Microsoft.AspNetCore.Mvc;\nusing System.Linq;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class HostHookController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"start-hoosthook\", async (args) =>\n                {\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    var options = new OpenDialogOptions\n                    {\n                        Properties = new OpenDialogProperty[]\n                        {\n                            OpenDialogProperty.openDirectory\n                        }\n                    };\n                    var folderPath = await Electron.Dialog.ShowOpenDialogAsync(mainWindow, options);\n\n                    var resultFromTypeScript = await Electron.HostHook.CallAsync<string>(\"create-excel-file\", folderPath);\n                    Electron.IpcMain.Send(mainWindow, \"excel-file-created\", resultFromTypeScript);\n                });\n            }\n\n            return View();\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/IpcController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing System.Linq;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class IpcController : Controller\n    {\n        public IActionResult Index()\n        {\n            if(HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"async-msg\", (args) =>\n                {\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    Electron.IpcMain.Send(mainWindow, \"asynchronous-reply\", \"pong\");\n                });\n\n                Electron.IpcMain.OnSync(\"sync-msg\", (args) =>\n                {\n                    return \"pong\";\n                });\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/ManageWindowsController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class WindowsController : Controller\n    {\n        public IActionResult Index()\n        {\n            string viewPath = $\"http://localhost:{BridgeSettings.WebPort}/windows/demowindow\";\n\n            Electron.IpcMain.On(\"new-window\", async (args) => {\n\n                await Electron.WindowManager.CreateWindowAsync(viewPath);\n\n            });\n\n            Electron.IpcMain.On(\"manage-window\", async (args) => {\n\n                var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);\n                browserWindow.OnMove += UpdateReply;\n                browserWindow.OnResize += UpdateReply;\n            });\n\n            Electron.IpcMain.On(\"listen-to-window\", async (args) => {\n                var mainBrowserWindow = Electron.WindowManager.BrowserWindows.First();\n\n                var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);\n                browserWindow.OnFocus += () => Electron.IpcMain.Send(mainBrowserWindow, \"listen-to-window-focus\");\n                browserWindow.OnBlur += () => Electron.IpcMain.Send(mainBrowserWindow, \"listen-to-window-blur\");\n\n                Electron.IpcMain.On(\"listen-to-window-set-focus\", (x) => browserWindow.Focus());\n            });\n\n            Electron.IpcMain.On(\"frameless-window\", async (args) => {\n                var options = new BrowserWindowOptions\n                {\n                    Frame = false\n                };\n                await Electron.WindowManager.CreateWindowAsync(options, viewPath);\n            });\n\n            return View();\n        }\n\n        private async void UpdateReply()\n        {\n            var browserWindow = Electron.WindowManager.BrowserWindows.Last();\n            var size = await browserWindow.GetSizeAsync();\n            var position = await browserWindow.GetPositionAsync();\n            string message = $\"Size: {size[0]},{size[1]} Position: {position[0]},{position[1]}\";\n\n            var mainWindow = Electron.WindowManager.BrowserWindows.First();\n            Electron.IpcMain.Send(mainWindow, \"manage-window-reply\", message);\n        }\n\n        public IActionResult DemoWindow()\n        {\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/MenusController.cs",
    "content": "﻿using System.Linq;\nusing Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API.Entities;\nusing ElectronNET.API;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class MenusController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                Electron.App.Ready += () => CreateContextMenu();\n\n                var menu = new MenuItem[] {\n                new MenuItem { Label = \"Edit\", Submenu = new MenuItem[] {\n                    new MenuItem { Label = \"Undo\", Accelerator = \"CmdOrCtrl+Z\", Role = MenuRole.undo },\n                    new MenuItem { Label = \"Redo\", Accelerator = \"Shift+CmdOrCtrl+Z\", Role = MenuRole.redo },\n                    new MenuItem { Type = MenuType.separator },\n                    new MenuItem { Label = \"Cut\", Accelerator = \"CmdOrCtrl+X\", Role = MenuRole.cut },\n                    new MenuItem { Label = \"Copy\", Accelerator = \"CmdOrCtrl+C\", Role = MenuRole.copy },\n                    new MenuItem { Label = \"Paste\", Accelerator = \"CmdOrCtrl+V\", Role = MenuRole.paste },\n                    new MenuItem { Label = \"Select All\", Accelerator = \"CmdOrCtrl+A\", Role = MenuRole.selectall }\n                }\n                },\n                new MenuItem { Label = \"View\", Submenu = new MenuItem[] {\n                    new MenuItem\n                    {\n                        Label = \"Reload\",\n                        Accelerator = \"CmdOrCtrl+R\",\n                        Click = () =>\n                        {\n                            // on reload, start fresh and close any old\n                            // open secondary windows\n                            var mainWindowId = Electron.WindowManager.BrowserWindows.ToList().First().Id;\n                            Electron.WindowManager.BrowserWindows.ToList().ForEach(browserWindow => {\n                                if(browserWindow.Id != mainWindowId)\n                                {\n                                    browserWindow.Close();\n                                }\n                                else\n                                {\n                                    browserWindow.Reload();\n                                }\n                            });\n                        }\n                    },\n                    new MenuItem\n                    {\n                        Label = \"Toggle Full Screen\",\n                        Accelerator = \"CmdOrCtrl+F\",\n                        Click = async () =>\n                        {\n                            bool isFullScreen = await Electron.WindowManager.BrowserWindows.First().IsFullScreenAsync();\n                            Electron.WindowManager.BrowserWindows.First().SetFullScreen(!isFullScreen);\n                        }\n                    },\n                    new MenuItem\n                    {\n                        Label = \"Open Developer Tools\",\n                        Accelerator = \"CmdOrCtrl+I\",\n                        Click = () => Electron.WindowManager.BrowserWindows.First().WebContents.OpenDevTools()\n                    },\n                    new MenuItem\n                    {\n                        Type = MenuType.separator\n                    },\n                    new MenuItem\n                    {\n                        Label = \"App Menu Demo\",\n                        Click = async () => {\n                            var options = new MessageBoxOptions(\"This demo is for the Menu section, showing how to create a clickable menu item in the application menu.\");\n                            options.Type = MessageBoxType.info;\n                            options.Title = \"Application Menu Demo\";\n                            await Electron.Dialog.ShowMessageBoxAsync(options);\n                        }\n                    }\n                }\n                },\n                new MenuItem { Label = \"Window\", Role = MenuRole.window, Submenu = new MenuItem[] {\n                     new MenuItem { Label = \"Minimize\", Accelerator = \"CmdOrCtrl+M\", Role = MenuRole.minimize },\n                     new MenuItem { Label = \"Close\", Accelerator = \"CmdOrCtrl+W\", Role = MenuRole.close }\n                }\n                },\n                new MenuItem { Label = \"Help\", Role = MenuRole.help, Submenu = new MenuItem[] {\n                    new MenuItem\n                    {\n                        Label = \"Learn More\",\n                        Click = async () => await Electron.Shell.OpenExternalAsync(\"https://github.com/ElectronNET\")\n                    }\n                }\n                }\n            };\n\n                Electron.Menu.SetApplicationMenu(menu);\n\n            }\n\n            return View();\n        }\n\n        private void CreateContextMenu()\n        {\n            var menu = new MenuItem[]\n            {\n                new MenuItem\n                {\n                    Label = \"Hello\",\n                    Click = async () => await Electron.Dialog.ShowMessageBoxAsync(\"Electron.NET rocks!\")\n                },\n                new MenuItem { Type = MenuType.separator },\n                new MenuItem { Label = \"Electron.NET\", Type = MenuType.checkbox, Checked = true }\n            };\n\n            var mainWindow = Electron.WindowManager.BrowserWindows.FirstOrDefault();\n            Electron.Menu.SetContextMenu(mainWindow, menu);\n\n            Electron.IpcMain.On(\"show-context-menu\", (args) =>\n            {\n                var mainWindow = Electron.WindowManager.BrowserWindows.FirstOrDefault();\n                Electron.Menu.ContextMenuPopup(mainWindow);\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/NotificationsController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class NotificationsController : Controller\n    {\n        public IActionResult Index()\n        {\n            if(HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"basic-noti\", (args) => {\n\n                    var options = new NotificationOptions(\"Basic Notification\", \"Short message part\")\n                    {\n                        OnClick = async () => await Electron.Dialog.ShowMessageBoxAsync(\"Notification clicked\")\n                    };\n\n                    Electron.Notification.Show(options);\n\n                });\n\n                Electron.IpcMain.On(\"advanced-noti\", (args) => {\n\n                    var options = new NotificationOptions(\"Notification with image\", \"Short message plus a custom image\")\n                    {\n                        OnClick = async () => await Electron.Dialog.ShowMessageBoxAsync(\"Notification clicked\"),\n                        Icon = \"/assets/img/programming.png\"\n                    };\n\n                    Electron.Notification.Show(options);\n                });\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/PdfController.cs",
    "content": "﻿using System.Linq;\nusing Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class PdfController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"print-pdf\", async (args) =>\n                {\n                    BrowserWindow mainWindow = Electron.WindowManager.BrowserWindows.First();\n\n                    var saveOptions = new SaveDialogOptions\n                    {\n                        Title = \"Save an PDF-File\",\n                        DefaultPath = await Electron.App.GetPathAsync(PathName.Documents),\n                        Filters = new FileFilter[]\n                        {\n                        new FileFilter { Name = \"PDF\", Extensions = new string[] { \"pdf\" } }\n                        }\n                    };\n                    var path = await Electron.Dialog.ShowSaveDialogAsync(mainWindow, saveOptions);\n\n                    if (await mainWindow.WebContents.PrintToPDFAsync(path))\n                    {\n                        await Electron.Shell.OpenExternalAsync(\"file://\" + path);\n                    }\n                    else\n                    {\n                        Electron.Dialog.ShowErrorBox(\"Error\", \"Failed to create pdf file.\");\n                    }\n                });\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/ShellController.cs",
    "content": "﻿using ElectronNET.API;\nusing ElectronNET.API.Entities;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class ShellController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"open-file-manager\", async (args) =>\n                {\n                    string path = await Electron.App.GetPathAsync(PathName.Home);\n                    await Electron.Shell.ShowItemInFolderAsync(path);\n\n                });\n\n                Electron.IpcMain.On(\"open-ex-links\", async (args) =>\n                {\n                    await Electron.Shell.OpenExternalAsync(\"https://github.com/ElectronNET\");\n                });\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/ShortcutsController.cs",
    "content": "﻿using ElectronNET.API;\nusing ElectronNET.API.Entities;\nusing Microsoft.AspNetCore.Mvc;\nusing System.Threading.Tasks;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class ShortcutsController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                Electron.GlobalShortcut.Register(\"CommandOrControl+Alt+K\", async () =>\n                {\n                    var options = new MessageBoxOptions(\"You pressed the registered global shortcut keybinding.\")\n                    {\n                        Type = MessageBoxType.info,\n                        Title = \"Success!\"\n                    };\n\n                    await Electron.Dialog.ShowMessageBoxAsync(options);\n                });\n                Electron.App.WillQuit += arg => Task.Run(() => Electron.GlobalShortcut.UnregisterAll());\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/TrayController.cs",
    "content": "﻿using System.IO;\nusing Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\nusing Microsoft.AspNetCore.Hosting;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class TrayController : Controller\n    {\n        private readonly IWebHostEnvironment _env;\n\n        public TrayController(IWebHostEnvironment env)\n        {\n            _env = env;\n        }\n\n\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                Electron.IpcMain.On(\"put-in-tray\", (args) =>\n                {\n\n                    if (Electron.Tray.MenuItems.Count == 0)\n                    {\n                        var menu = new MenuItem\n                        {\n                            Label = \"Remove\",\n                            Click = () => Electron.Tray.Destroy()\n                        };\n\n                        Electron.Tray.Show(Path.Combine(_env.ContentRootPath, \"Assets/electron_32x32.png\"), menu);\n                        Electron.Tray.SetToolTip(\"Electron Demo in the tray.\");\n                    }\n                    else\n                    {\n                        Electron.Tray.Destroy();\n                    }\n\n                });\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/UpdateController.cs",
    "content": "﻿using System.Linq;\nusing ElectronNET.API;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class UpdateController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                Electron.AutoUpdater.OnError += (message) => Electron.Dialog.ShowErrorBox(\"Error\", message);\n                Electron.AutoUpdater.OnCheckingForUpdate += async () => await Electron.Dialog.ShowMessageBoxAsync(\"Checking for Update\");\n                Electron.AutoUpdater.OnUpdateNotAvailable += async (info) => await Electron.Dialog.ShowMessageBoxAsync(\"Update not available\");\n                Electron.AutoUpdater.OnUpdateAvailable += async (info) => await Electron.Dialog.ShowMessageBoxAsync(\"Update available\" + info.Version);\n                Electron.AutoUpdater.OnDownloadProgress += (info) =>\n                {\n                    var message1 = \"Download speed: \" + info.BytesPerSecond + \"\\n<br/>\";\n                    var message2 = \"Downloaded \" + info.Percent + \"%\" + \"\\n<br/>\";\n                    var message3 = $\"({info.Transferred}/{info.Total})\" + \"\\n<br/>\";\n                    var message4 = \"Progress: \" + info.Progress + \"\\n<br/>\";\n                    var information = message1 + message2 + message3 + message4;\n\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    Electron.IpcMain.Send(mainWindow, \"auto-update-reply\", information);\n                };\n                Electron.AutoUpdater.OnUpdateDownloaded += async (info) => await Electron.Dialog.ShowMessageBoxAsync(\"Update complete!\" + info.Version);\n\n                Electron.IpcMain.On(\"auto-update\", async (args) =>\n                {\n                    // Electron.NET CLI Command for deploy:\n                    // electronize build /target win /electron-params --publish=always\n\n                    var currentVersion = await Electron.App.GetVersionAsync();\n                    var updateCheckResult = await Electron.AutoUpdater.CheckForUpdatesAndNotifyAsync();\n                    var availableVersion = updateCheckResult.UpdateInfo.Version;\n                    string information = $\"Current version: {currentVersion} - available version: {availableVersion}\";\n\n                    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n                    Electron.IpcMain.Send(mainWindow, \"auto-update-reply\", information);\n                });\n            }\n\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Controllers/WindowsController.cs",
    "content": "﻿using System.Linq;\nusing Microsoft.AspNetCore.Mvc;\nusing ElectronNET.API;\nusing ElectronNET.API.Entities;\n\nnamespace ElectronNET.WebApp.Controllers\n{\n    public class WindowsController : Controller\n    {\n        public IActionResult Index()\n        {\n            if (HybridSupport.IsElectronActive)\n            {\n                string viewPath = $\"http://localhost:{ElectronNetRuntime.AspNetWebPort}/windows/demowindow\";\n\n                Electron.IpcMain.On(\"new-window\", async (args) =>\n                {\n                    await Electron.WindowManager.CreateWindowAsync(viewPath);\n                });\n\n                Electron.IpcMain.On(\"manage-window\", async (args) =>\n                {\n\n                    var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);\n                    browserWindow.OnMove += UpdateReply;\n                    browserWindow.OnResize += UpdateReply;\n                });\n\n                Electron.IpcMain.On(\"listen-to-window\", async (args) =>\n                {\n                    var mainBrowserWindow = Electron.WindowManager.BrowserWindows.First();\n\n                    var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);\n                    browserWindow.OnFocus += () => Electron.IpcMain.Send(mainBrowserWindow, \"listen-to-window-focus\");\n                    browserWindow.OnBlur += () => Electron.IpcMain.Send(mainBrowserWindow, \"listen-to-window-blur\");\n\n                    _ = Electron.IpcMain.On(\"listen-to-window-set-focus\", (x) => browserWindow.Focus());\n                });\n\n                Electron.IpcMain.On(\"frameless-window\", async (args) =>\n                {\n                    var options = new BrowserWindowOptions\n                    {\n                        Frame = false\n                    };\n                    await Electron.WindowManager.CreateWindowAsync(options, viewPath);\n                });\n            }\n\n            return View();\n        }\n\n        private async void UpdateReply()\n        {\n            var browserWindow = Electron.WindowManager.BrowserWindows.Last();\n            var size = await browserWindow.GetSizeAsync();\n            var position = await browserWindow.GetPositionAsync();\n            string message = $\"Size: {size[0]},{size[1]} Position: {position[0]},{position[1]}\";\n\n            var mainWindow = Electron.WindowManager.BrowserWindows.First();\n            Electron.IpcMain.Send(mainWindow, \"manage-window-reply\", message);\n        }\n\n        public IActionResult DemoWindow()\n        {\n            return View();\n        }\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronHostHook/.gitignore",
    "content": "\n# Created by https://www.gitignore.io/api/node\n# Edit at https://www.gitignore.io/?templates=node\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# next.js build output\n.next\n\n# nuxt.js build output\n.nuxt\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# End of https://www.gitignore.io/api/node"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronHostHook/connector.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Connector = void 0;\nclass Connector {\n    constructor(socket, app) {\n        this.socket = socket;\n        this.app = app;\n    }\n    on(key, javaScriptCode) {\n        this.socket.on(key, (...args) => {\n            const id = args.pop();\n            try {\n                javaScriptCode(...args, (data) => {\n                    if (data) {\n                        this.socket.emit(`${key}Complete${id}`, data);\n                    }\n                });\n            }\n            catch (error) {\n                this.socket.emit(`${key}Error${id}`, `Host Hook Exception`, error);\n            }\n        });\n    }\n}\nexports.Connector = Connector;\n//# sourceMappingURL=connector.js.map"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronHostHook/connector.ts",
    "content": "import { Socket } from 'socket.io';\n\nexport class Connector {\n    constructor(private socket: Socket,\n        public app: any) { }\n\n    on(key: string, javaScriptCode: Function): void {\n        this.socket.on(key, (...args: any[]) => {\n            const id: string = args.pop();\n\n            try {\n                javaScriptCode(...args, (data) => {\n                    if (data) {\n                        this.socket.emit(`${key}Complete${id}`, data);\n                    }\n                });\n            } catch (error) {\n                this.socket.emit(`${key}Error${id}`, `Host Hook Exception`, error);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronHostHook/excelCreator.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.ExcelCreator = void 0;\nconst exceljs_1 = require(\"exceljs\");\nclass ExcelCreator {\n    async create(path) {\n        const workbook = new exceljs_1.Workbook();\n        const worksheet = workbook.addWorksheet(\"My Sheet\");\n        worksheet.columns = [\n            { header: \"Id\", key: \"id\", width: 10 },\n            { header: \"Name\", key: \"name\", width: 32 },\n            { header: \"Birthday\", key: \"birthday\", width: 10, outlineLevel: 1 }\n        ];\n        worksheet.addRow({ id: 1, name: \"John Doe\", birthday: new Date(1970, 1, 1) });\n        worksheet.addRow({ id: 2, name: \"Jane Doe\", birthday: new Date(1965, 1, 7) });\n        await workbook.xlsx.writeFile(path + \"\\\\sample.xlsx\");\n        return \"Excel file created YAY YAY!\";\n    }\n}\nexports.ExcelCreator = ExcelCreator;\n//# sourceMappingURL=excelCreator.js.map"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronHostHook/excelCreator.ts",
    "content": "import { Workbook, Worksheet } from \"exceljs\";\n\nexport class ExcelCreator {\n    async create(path: string): Promise<string> {\n        const workbook: Workbook = new Workbook();\n        const worksheet: Worksheet = workbook.addWorksheet(\"My Sheet\");\n        worksheet.columns = [\n            { header: \"Id\", key: \"id\", width: 10 },\n            { header: \"Name\", key: \"name\", width: 32 },\n            { header: \"Birthday\", key: \"birthday\", width: 10, outlineLevel: 1 }\n        ];\n        worksheet.addRow({ id: 1, name: \"John Doe\", birthday: new Date(1970, 1, 1) });\n        worksheet.addRow({ id: 2, name: \"Jane Doe\", birthday: new Date(1965, 1, 7) });\n\n        await workbook.xlsx.writeFile(path + \"\\\\sample.xlsx\");\n\n        return \"Excel file created YAY YAY!\";\n    }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronHostHook/index.js",
    "content": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.HookService = void 0;\nconst connector_1 = require(\"./connector\");\nconst excelCreator_1 = require(\"./excelCreator\");\nclass HookService extends connector_1.Connector {\n    constructor(socket, app) {\n        super(socket, app);\n        this.app = app;\n    }\n    onHostReady() {\n        // execute your own JavaScript Host logic here\n        this.on(\"create-excel-file\", async (path, done) => {\n            const excelCreator = new excelCreator_1.ExcelCreator();\n            const result = await excelCreator.create(path);\n            done(result);\n        });\n    }\n}\nexports.HookService = HookService;\n//# sourceMappingURL=index.js.map"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronHostHook/index.ts",
    "content": "import { Connector } from \"./connector\";\nimport { Socket } from \"socket.io\";\nimport { ExcelCreator } from './excelCreator';\n\nexport class HookService extends Connector {\n    constructor(socket: Socket, public app: any) {\n        super(socket, app);\n    }\n\n    onHostReady(): void {\n        // execute your own JavaScript Host logic here\n        this.on(\"create-excel-file\", async (path, done) => {\n            const excelCreator: ExcelCreator = new ExcelCreator();\n            const result: string = await excelCreator.create(path);\n\n            done(result);\n        });\n    }\n}\n\n"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronHostHook/package.json",
    "content": "{\n  \"name\": \"electron-host-hook\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Connector for Electron.NET projects.\",\n  \"repository\": {\n    \"url\": \"https://github.com/ElectronNET/Electron.NET\"\n  },\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"keywords\": [],\n  \"author\": \"Gregor Biswanger\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"eslint\": \"^9.37.0\",\n    \"typescript\": \"^5.9.3\"\n  },\n    \"dependencies\": {\n    \"archiver-utils\": \"^2.1.0\",\n    \"socket.io\": \"^4.8.1\",\n    \"exceljs\": \"^1.10.0\"\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronHostHook/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"target\": \"ES2019\",\n    \"sourceMap\": true,\n    \"skipLibCheck\": true\n  },\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/ElectronNET.WebApp.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <!-- When this is enabled, the project will be switched from nuget packages to consuming the ElectronNet orchestration directly -->\n    <ElectronNetDevMode>true</ElectronNetDevMode>\n  </PropertyGroup>\n\n  <Import Project=\"..\\ElectronNET\\build\\ElectronNET.Core.props\" Condition=\"$(ElectronNetDevMode)\" />\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>\n    <AspNetCoreModuleName>AspNetCoreModule</AspNetCoreModuleName>\n  </PropertyGroup>\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <ImportNuGetBuildTasksPackTargetsFromSdk>false</ImportNuGetBuildTasksPackTargetsFromSdk>\n    <PublishTrimmed>false</PublishTrimmed>\n    <NuGetAudit>false</NuGetAudit>\n  </PropertyGroup>\n  <PropertyGroup Label=\"ElectronNetCommon\">\n    <PackageIcon>128.png</PackageIcon>\n    <ApplicationIcon>wwwroot\\assets\\app-icon\\win\\app.ico</ApplicationIcon>\n    <NoWin32Manifest>true</NoWin32Manifest>\n    <ElectronIcon>wwwroot\\assets\\app-icon\\win\\app.ico</ElectronIcon>\n    <Title>ElectronNET API Demo1</Title>\n    <Version>1.0.2</Version>\n    <Product>com.electronnet-apisamples.app</Product>\n    <Description>Electron.NET Demo Application</Description>\n    <Company>Electron.Net</Company>\n    <Copyright>Copyright © 2025, Electron.NET</Copyright>\n    <PackageTags>Electron;.NET;ASP;NET;Sample;App</PackageTags>\n    <ElectronVersion>30.4.0</ElectronVersion>\n    <ElectronSplashScreen>wwwroot\\assets\\img\\about@2x.png</ElectronSplashScreen>\n    <License>MIT</License>\n    <ElectronSingleInstance>false</ElectronSingleInstance>\n    <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n    <ElectronBuilderVersion>26.0</ElectronBuilderVersion>\n  </PropertyGroup>\n  <PropertyGroup>\n    <TypeScriptModuleKind>commonjs</TypeScriptModuleKind>\n    <TypeScriptUseNodeJS>true</TypeScriptUseNodeJS>\n    <TypeScriptTSConfig>ElectronHostHook/tsconfig.json</TypeScriptTSConfig>\n  </PropertyGroup>\n  <PropertyGroup>\n    <TypeScriptCompileOnSaveEnabled>true</TypeScriptCompileOnSaveEnabled>\n    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>\n    <Nullable>disable</Nullable>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Remove=\"publish\\**\" />\n    <Content Remove=\"publish\\**\" />\n    <EmbeddedResource Remove=\"publish\\**\" />\n    <None Remove=\"publish\\**\" />\n    <TypeScriptCompile Remove=\"**\\node_modules\\**\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Remove=\"Controllers\\ManageWindowsController.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Remove=\"Views\\Windows\\HandleErrorCrashes.cshtml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Folder Include=\"wwwroot\\assets\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Update=\"Assets\\electron.ico\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"Assets\\electron_32x32.png\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ElectronNET.API\\ElectronNET.API.csproj\" Condition=\"$(ElectronNetDevMode)\" />\n    <ProjectReference Include=\"..\\ElectronNET.AspNet\\ElectronNET.AspNet.csproj\" Condition=\"$(ElectronNetDevMode)\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"ElectronNET.Core\" Version=\"0.4.1\" Condition=\"'$(ElectronNetDevMode)' != 'true'\" />\n    <PackageReference Include=\"ElectronNET.Core.AspNet\" Version=\"0.4.1\" Condition=\"'$(ElectronNetDevMode)' != 'true'\" />\n    <PackageReference Include=\"Microsoft.TypeScript.MSBuild\" Version=\"5.9.3\" />\n  </ItemGroup>\n\n  <Import Project=\"..\\ElectronNET\\build\\ElectronNET.Core.targets\" Condition=\"$(ElectronNetDevMode)\" />\n\n</Project>"
  },
  {
    "path": "src/ElectronNET.WebApp/Program.cs",
    "content": "﻿using ElectronNET.API;\nusing Microsoft.AspNetCore;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Logging;\n\nnamespace ElectronNET.WebApp\n{\n    using System.Threading.Tasks;\n    using ElectronNET.API.Entities;\n\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateWebHostBuilder(args).Build().Run();\n        }\n\n        public static IWebHostBuilder CreateWebHostBuilder(string[] args)\n        {\n            return WebHost.CreateDefaultBuilder(args)\n                .ConfigureLogging((hostingContext, logging) => { logging.AddConsole(); })\n                .UseElectron(args, ElectronBootstrap)\n                .UseStartup<Startup>();\n        }\n\n        public static async Task ElectronBootstrap()\n        {\n            //AddDevelopmentTests();\n\n            var browserWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions\n            {\n                Width = 1152,\n                Height = 940,\n                Show = false\n            });\n\n            await browserWindow.WebContents.Session.ClearCacheAsync();\n\n            browserWindow.OnReadyToShow += () => browserWindow.Show();\n        }\n\n        private static void AddDevelopmentTests()\n        {\n            // NOTE: on mac you will need to allow the app to post notifications when asked.\n\n            _ = Electron.App.On(\"activate\", (obj) =>\n            {\n                // obj should be a boolean that represents where there are active windows or not.\n                var hasWindows = (bool)obj;\n\n                Electron.Notification.Show(\n                    new NotificationOptions(\"Activate\", $\"activate event has been captured. Active windows = {hasWindows}\")\n                    {\n                        Silent = false,\n                    });\n            });\n\n            if (System.OperatingSystem.IsMacOS())\n            {\n                Electron.Dock.SetMenu(new[]\n                {\n                    new MenuItem\n                    {\n                        Type = MenuType.normal,\n                        Label = \"MenuItem\",\n                        Click = () =>\n                        {\n                            Electron.Notification.Show(new NotificationOptions(\n                                \"Dock MenuItem Click\",\n                                \"A menu item added to the Dock was selected;\"));\n                        },\n                    },\n                    new MenuItem\n                    {\n                        Type = MenuType.submenu,\n                        Label = \"SubMenu\",\n                        Submenu = new[]\n                        {\n                            new MenuItem\n                            {\n                                Type = MenuType.normal,\n                                Label = \"Sub MenuItem\",\n                                Click = () =>\n                                {\n                                    Electron.Notification.Show(new NotificationOptions(\n                                        \"Dock Sub MenuItem Click\",\n                                        \"A menu item added to the Dock was selected;\"));\n                                },\n                            },\n                        }\n                    }\n                });\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Properties/PublishProfiles/linux-x64.pubxml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->\n<Project>\n  <PropertyGroup>\n    <DeleteExistingFiles>true</DeleteExistingFiles>\n    <ExcludeApp_Data>false</ExcludeApp_Data>\n    <LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>\n    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>\n    <PublishProvider>FileSystem</PublishProvider>\n    <PublishUrl>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishUrl>\n    <WebPublishMethod>FileSystem</WebPublishMethod>\n    <_TargetId>Folder</_TargetId>\n    <SiteUrlToLaunchAfterPublish />\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>\n    <ProjectGuid>6ea447d9-343f-46b8-b456-66557bddbb9f</ProjectGuid>\n    <SelfContained>true</SelfContained>\n    <LastUsedPlatform>Any CPU</LastUsedPlatform>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "src/ElectronNET.WebApp/Properties/PublishProfiles/win-x64.pubxml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->\n<Project>\n  <PropertyGroup>\n    <DeleteExistingFiles>true</DeleteExistingFiles>\n    <ExcludeApp_Data>false</ExcludeApp_Data>\n    <LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>\n    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>\n    <PublishProvider>FileSystem</PublishProvider>\n    <PublishUrl>publish\\$(Configuration)\\$(TargetFramework)\\$(RuntimeIdentifier)\\</PublishUrl>\n    <WebPublishMethod>FileSystem</WebPublishMethod>\n    <_TargetId>Folder</_TargetId>\n    <SiteUrlToLaunchAfterPublish />\n    <TargetFramework>net10.0</TargetFramework>\n    <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n    <ProjectGuid>6ea447d9-343f-46b8-b456-66557bddbb9f</ProjectGuid>\n    <SelfContained>true</SelfContained>\n    <LastUsedPlatform>Any CPU</LastUsedPlatform>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "src/ElectronNET.WebApp/Properties/electron-builder.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/electron-userland/electron-builder/refs/heads/master/packages/app-builder-lib/scheme.json\",\n  \"compression\": \"maximum\",\n  //\"afterPack\": \"bin/Assets/afterPack.js\",\n  //\"beforePack\": \"bin/Assets/beforePack.js\",\n  \"buildNumber\": \"\",\n  \"linux\": {\n    \"target\": [\n      \"tar.xz\"\n      //\"AppImage\",\n      //\"rpm\",\n      //\"deb\",\n      //\"pacman\"\n    ],\n    \"executableArgs\": [ \"--no-sandbox\" ],\n    \"icon\": \"bin/Assets/icon.png\",\n    \"artifactName\": \"${name}-${arch}-${version}.${ext}\"\n  },\n  \"win\": {\n    \"target\": [\n      {\n        \"target\": \"portable\",\n        \"arch\": \"x64\"\n      }\n    ],\n    \"icon\": \"bin/Assets/icon.ico\"\n  },\n  \"mac\": {\n    \"icon\": \"bin/Assets/icon.icns\"\n  }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"ASP.Net (unpackaged)\": {\n      \"commandName\": \"Project\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      },\n      \"applicationUrl\": \"http://localhost:8001/\"\n    },\n    \"Electron (unpackaged)\": {\n      \"commandName\": \"Executable\",\n      \"executablePath\": \"node\",\n      \"commandLineArgs\": \"node_modules/electron/cli.js main.js -unpackedelectron\",\n      \"workingDirectory\": \"$(TargetDir).electron\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"WSL\": {\n      \"commandName\": \"WSL2\",\n      \"launchUrl\": \"http://localhost:8001/\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_URLS\": \"http://localhost:8001/\"\n      },\n      \"distributionName\": \"\"\n    }\n  }\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/Startup.cs",
    "content": "﻿using Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\n\nnamespace ElectronNET.WebApp\n{\n    public class Startup\n    {\n        public IConfiguration Configuration { get; }\n\n        public Startup(IConfiguration configuration)\n        {\n            Configuration = configuration;\n        }\n\n        // This method gets called by the runtime. Use this method to add services to the container.\n        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940\n        public void ConfigureServices(IServiceCollection services)\n        {\n            services.AddMvc();\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n\n            app.UseStaticFiles();\n\n            app.UseRouting();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapControllerRoute(\"default\", \"{controller=Home}/{action=Index}/{id?}\");\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/About/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <div id=\"about-modal\" class=\"about modal\">\n        <div class=\"about-wrapper\">\n            <header class=\"about-header\">\n                <img class=\"about-logo\" src=\"assets/img/about.png\" srcset=\"assets/img/about.png 1x, assets/img/about@2x.png 2x\" alt=\"Electron.NET API Demos\">\n            </header>\n            <main class=\"about-sections\">\n                <section class=\"about-section play-along\">\n                    <h2>Play Along</h2>\n                    <p>Use the demo snippets in an Electron app of your own. The <a href=\"https://github.com/electron/electron-quick-start\">Electron Quick Start<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a> app is a bare-bones setup that pairs with these demos. Follow the instructions here to get it going.\n                    To activate Electron.NET include the <a href=\"https://www.nuget.org/packages/ElectronNET.Core/\" target=\"_blank\">ElectronNET.API NuGet package</a> in your ASP.NET Core app.\n                    <p>\n                        <code class=\"language-bash\">dotnet add package ElectronNET.Core</code>\n                    </p>\n\n                    Then include the UseElectron WebHostBuilder-Extension into the Program.cs-file of your ASP.NET Core project.\n\n                    <pre>\n                        <code class=\"csharp\">public static IWebHost BuildWebHost(string[] args)\n{\n    return WebHost.CreateDefaultBuilder(args)\n        .UseElectron(args)\n        .UseStartup&lt;Startup&gt;()\n        .Build();\n}</code>\n                    </pre>\n                </section>\n                <section class=\"about-section about-code\">\n                    <h2>About the Code</h2>\n                    <p>The source code of this app has been organized with ease of navigation in mind.\n                    You will find for each API Category the source code into the Controllers. \n                    This Demo-App based on the <a href=\"https://github.com/electron/electron-api-demos\" target=\"_blank\">Electron API Demos</a>.</p> \n                </section>\n                <footer class=\"about-section footer\">\n                    <div class=\"rainbow-button-wrapper\">\n                        <button id=\"get-started\" class=\"about-button modal-hide\">Get Started</button>\n                    </div>\n                </footer>\n            </main>\n        </div>\n    </div>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/AppSysInformation/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"app-sys-information-section\" class=\"section js-section u-category-system\">\n        <header class=\"section-header\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-system\"></use></svg>\n                    Get app and system information\n                </h1>\n                <h3>With Electron.NET you can gather information about the user's system, app or screen.</h3>\n                \n                <p>You find the sample source code in <code>Controllers\\AppSysInformationController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"app-info-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Get app information\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"app-info\">View Demo</button>\n                        <span class=\"demo-response\" id=\"got-app-info\"></span>\n                    </div>\n                    <p>The main process <code>Electron.App</code> can be used to get the path at which your app is located on the user's computer.</p>\n                    <p>In this example, to get that information from the renderer process, we use the <code>ipcRenderer</code> to send a message to the main process requesting the app's path.</p>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"javascript\">const { ipcRenderer } = require(\"electron\");\n\ndocument.getElementById(\"app-info\").addEventListener(\"click\", () => {\n    ipcRenderer.send(\"app-info\");\n});\n\nipcRenderer.on(\"got-app-path\", (event, path) => {\n    const message = `This app is located at: ${path}`;\n    document.getElementById('got-app-info').innerHTML = message\n});</code></pre>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"app-info\", async (args) => \n{\n    string appPath = await Electron.App.GetAppPathAsync();\n\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    Electron.IpcMain.Send(mainWindow, \"got-app-path\", appPath);\n});</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"app-version-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Get version information\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"version-info\">View Demo</button>\n                        <span class=\"demo-response\" id=\"got-version-info\"></span>\n                    </div>\n                    <p>The <code>process</code> module is built into Node.js (therefore you can use this in the renderer processes) and in Electron.NET apps this object has a few more useful properties on it.</p>\n                    <p>The example below gets the version of Electron in use by the app.</p>\n                    <p>See the <a href=\"http://electron.atom.io/docs/api/process\">process documentation<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a> for more.</p>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"javascript\">document.getElementById('version-info').addEventListener('click', () => {\n    const electronVersion = process.versions.electron;\n    const message = `This app is using Electron version: ${electronVersion}`;\n    document.getElementById('got-version-info').innerHTML = message;\n});</code></pre>\n\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Find versions of Chromium, Node.js and V8.</strong>\n                        <p>Electron also includes versions of Chromium, Node.js and V8 within the <code>process.versions</code> object. You can get there quickly by opening up developer tools in an Electron app and typing <code>process.versions</code>.</p>\n                        <pre><code class=\"language-js\">// Returns version of Chromium in use\nprocess.versions.chrome\n// Returns version of V8 in use\nprocess.versions.v8\n// Returns version of Node in use\nprocess.versions.node</code></pre>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"sys-info-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Get system information\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"sys-info\">View Demo</button>\n                        <span class=\"demo-response\" id=\"got-sys-info\"></span>\n                    </div>\n                    <p>In the example below we require the module and then return the location of the home directory.</p>\n\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"sys-info\", async (args) =>\n{\n    string homePath = await Electron.App.GetPathAsync(PathName.home);\n\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    Electron.IpcMain.Send(mainWindow, \"got-sys-info\", homePath);\n});</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"screen-info-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Get screen information\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"screen-info\">View Demo</button>\n                        <span class=\"demo-response\" id=\"got-screen-info\"></span>\n                    </div>\n                    <p>The <code>Electron.Screen</code> retrieves information about screen size, displays, cursor position, etc. In the example below we retrieve the dimensions of the monitor in use.</p>\n\n                    <p>See the full <a href=\"http://electron.atom.io/docs/api/screen\">screen documentation<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a> for more.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"screen-info\", async (args) =>\n{\n    var display = await Electron.Screen.GetPrimaryDisplayAsync();\n\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    Electron.IpcMain.Send(mainWindow, \"got-screen-info\", display.Size);\n});</code></pre>\n\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Differences in dimensions.</strong>\n                        <p>The <code>.Size</code> property in the example returns the raw dimensions of the screen but because of system menu bars this may not be the actual space available for your app.</p>\n\n                        <p>To get the dimensions of the available screen space use the <code>.WorkAreaSize</code> property. Using <code>.workArea</code> will return the coordinates as well as the dimensions of the available screen space.</p>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <script>\n            (function(){\n                const { ipcRenderer } = require(\"electron\");\n                \n                document.getElementById(\"app-info\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"app-info\");\n                });\n\n                ipcRenderer.on(\"got-app-path\", (event, path) => {\n                    const message = `This app is located at: ${path}`;\n                    document.getElementById('got-app-info').innerHTML = message;\n                });\n\n                document.getElementById('version-info').addEventListener('click', () => {\n                    const electronVersion = process.versions.electron;\n                    const message = `This app is using Electron version: ${electronVersion}`;\n                    document.getElementById('got-version-info').innerHTML = message;\n                });\n\n                document.getElementById('sys-info').addEventListener('click', () => {\n                    ipcRenderer.send(\"sys-info\");\n                });\n\n                ipcRenderer.on(\"got-sys-info\", (event, homeDir) => {\n                    const message = `Your system home directory is: ${homeDir}`;\n                    document.getElementById('got-sys-info').innerHTML = message;\n                });\n\n                document.getElementById(\"screen-info\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"screen-info\");\n                });\n                \n                ipcRenderer.on(\"got-screen-info\", (event, size) => {\n                     const message = `Your screen is: ${size.width}px x ${size.height}px`;\n                     document.getElementById('got-screen-info').innerHTML = message;\n                });\n\n            }());\n        </script>\n\n    </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Clipboard/Index.cshtml",
    "content": "<template class=\"task-template\">\n    <section id=\"clipboard-section\" class=\"section js-section u-category-system\">\n        <header class=\"section-header\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-system\"></use></svg>\n                    Clipboard\n                </h1>\n                <h3>The <code>Electron.Clipboard</code> provides methods to perform copy and paste operations.</h3>\n                <p>This module also has methods for copying text as markup (HTML) to the clipboard.</p>\n\n                <p>You find the sample source code in <code>Controllers\\ClipboardController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"copy-to-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Copy\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"copy-to\">Copy</button>\n                        <input class=\"demo-input\" id=\"copy-to-input\" aria-label=\"Click copy\" placeholder=\"Click copy.\"></input>\n                    </div>\n                    <p>In this example we copy a phrase to the clipboard. After clicking 'Copy' use the text area to paste (CMD + V or CTRL + V) the phrase from the clipboard.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"copy-to\", (text) => \n{\n    Electron.Clipboard.WriteText(text.ToString());\n});</code></pre>\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Electron.js Support in Electron.NET.</strong>\n                        <p>The <code>clipboard</code> module is built into Electron.js (therefore you can use this in the renderer processes).</p>\n                        <pre><code class=\"language-js\">const clipboard = require('electron').clipboard;\n\nconst copyBtn = document.getElementById('copy-to');\nconst copyInput = document.getElementById('copy-to-input');\n\ncopyBtn.addEventListener('click', () => {\n  if (copyInput.value !== '') copyInput.value = '';\n  copyInput.placeholder = 'Copied! Paste here to see.';\n  clipboard.writeText('Electron Demo!');\n})</code></pre>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"paste-to-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Paste\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"paste-to\">Paste</button>\n                        <span class=\"demo-response\" id=\"paste-from\"></span>\n                    </div>\n                    <p>In this example we copy a string to the clipboard and then paste the results into a message above.</p>\n\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"paste-to\", async (text) =>\n{\n    Electron.Clipboard.WriteText(text.ToString());\n    string pasteText = await Electron.Clipboard.ReadTextAsync();\n\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    Electron.IpcMain.Send(mainWindow, \"paste-from\", pasteText);\n});</code></pre>\n\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Electron.js Support in Electron.NET.</strong>\n                        <p>The <code>clipboard</code> module is built into Electron.js (therefore you can use this in the renderer processes).</p>\n                        <pre><code class=\"language-js\">const clipboard = require('electron').clipboard;\n\nconst pasteBtn = document.getElementById('paste-to');\n\npasteBtn.addEventListener('click', () => {\n  clipboard.writeText('What a demo!');\n  const message = `Clipboard contents: ${clipboard.readText()}`;\n  document.getElementById('paste-from').innerHTML = message;\n})</code></pre>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"copy-to-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Copy Image\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"copy-image-to\">Copy</button>\n                        <textarea id=\"paste-image-div\" onpaste=\"console.log('onpastefromhtml')\"></textarea>\n                        <div class=\"demo-image-box\" id=\"image-paste-div\"></div>\n                    </div>\n                    <p>In this example we copy an image to the Clipboard. After clicking 'Copy' use the text area to paste (CMD + V or CTRL + V) the image from the clipboard.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"copy-image-to\", async (test) =>\n{\n    var nativeImage = NativeImage.CreateFromDataURL(test.ToString());\n    Electron.Clipboard.WriteImage(nativeImage);\n});</code></pre>\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Electron.js Support in Electron.NET.</strong>\n                        <p>The <code>clipboard</code> module is built into Electron.js (therefore you can use this in the renderer processes).</p>\n                        <pre><code class=\"language-js\">const { nativeImage, clipboard } = require('electron');\n\nconst copyBtn = document.getElementById('copy-to-image');\nconst imageDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACmklEQVR42oVTX0hTURj/zr2b07utMR0st2m30UxZJRHpWNDjRkUPvgUZQdGD4Esq6yWf9EVx9iL4EAiBVNDDHqxs9RBI+ZcorLVSkemcNdmct827Oe92Ot1b270i9MHHOfc73/f7fvd3zofggGU/OD1k8RJ3E2/6Gw4TnyYerDoXei3PR/82uwtOliydlJbtoA1OhtY7AFVZxDOc3YRiegkELsRjPjKKMYxoz3+NlAAyc00sBuhTm9ztavNFoBizhIqVbYrZOOzHp0DYmhkHhHt1reGIePTrfeOQ2tzaranzAqI1cmJlw1IYF3KwF30F+a0Fv8Ed7kHbU40elc4SYOxXGJoxibmDl++D70W/AkeMvewX94VsEvjV57yQjrWhxNuTfsbW0lVlaynxHbw6AL4Jn9QSkdb4QIzQ4TfmIbsxP4zibxpmjE6vS33EfCjzEn+MFHrkuTikQsFZFJt07BxtvWSgVBXwX8MyQYU8xOcmObQ+cWLH6rpAANQy2RU3LKssX0tR2IfY7DsOrQbsM7VnHK5Kg04S69o8+J62HEpAfpbjMvBjcXkWrTw77jeyxq7qeqOUdH0J2u7pwNFsUbyF5cVNCAxkwPe4QfxORVKQXNsZRt+esJ5KvSpQ26hnKrQ0JBI5GLvLSSCntFLxl12x+NYDA5hqNJDnC/Dze4bPpgtt4o+Gxo8NGS10t9lOA6VCkEhViCByE4ur96C4j2BrVYDtWMHvvLHWIwJ8flTPEqp91dZie40Ng0ZbFIVKxCT+JqsEsscjSEYpUkyRpwy9p2+uR0pSfxqrYxFGnYxB6NDXCIzOKEDlHyCSkctQkEmpIJ1U8TxHj5L0kebb0fIwye3jQ5uH9PUiQIpxxoCnSSx49k5UMc6/ARiuBRgyrEC3AAAAAElFTkSuQmCC';\n\ncopyBtn.addEventListener('click', () => {\n    var image = nativeImage.CreateFromDataURL(imageDataUrl);\n    clipboard.WriteImage(image);\n})\n</code></pre>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"copy-to-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Paste Image\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"paste-image-from\">Paste</button>\n                        <img class=\"demo-image-box\" id=\"paste-image-from-div\"></img>\n                    </div>\n                    <p>In this example we paste an image from the Clipboard. After clicking 'Paste', if your clipboard contained an image, the image will show up next to the paste button.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"paste-image-to\", async test =>\n{\n    var nativeImage = await Electron.Clipboard.ReadImageAsync();\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    Electron.IpcMain.Send(mainWindow, \"paste-image-from\", JSON.stringify(nativeImage));\n});</code></pre>\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Electron.js Support in Electron.NET.</strong>\n                        <p>The <code>clipboard</code> module is built into Electron.js (therefore you can use this in the renderer processes).</p>\n                        <pre><code class=\"language-js\">const { nativeImage, clipboard } = require('electron');\n\nconst pasteBtn = document.getElementById('paste-to-image');\n\ncopyBtn.addEventListener('click', () => {\n    const image = clipboard.readImage();\n    document.getElementById('image-holder').src = image.toDataURL();\n})</code></pre>\n                    </div>\n                </div>\n            </div>\n        </div>\n        \n        <script>\n            (function () {\n                const { ipcRenderer, nativeImage } = require(\"electron\");\n\n                document.getElementById(\"copy-to\").addEventListener(\"click\", () => {\n                    document.getElementById('copy-to-input').placeholder = 'Copied! Paste here to see.';\n                    ipcRenderer.send(\"copy-to\", \"Electron.NET Demo!\");\n                });\n\n                document.getElementById(\"paste-to\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"paste-to\", \"What a demo!\");\n                });\n\n                document.getElementById(\"copy-image-to\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"copy-image-to\", 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACmklEQVR42oVTX0hTURj/zr2b07utMR0st2m30UxZJRHpWNDjRkUPvgUZQdGD4Esq6yWf9EVx9iL4EAiBVNDDHqxs9RBI+ZcorLVSkemcNdmct827Oe92Ot1b270i9MHHOfc73/f7fvd3zofggGU/OD1k8RJ3E2/6Gw4TnyYerDoXei3PR/82uwtOliydlJbtoA1OhtY7AFVZxDOc3YRiegkELsRjPjKKMYxoz3+NlAAyc00sBuhTm9ztavNFoBizhIqVbYrZOOzHp0DYmhkHhHt1reGIePTrfeOQ2tzaranzAqI1cmJlw1IYF3KwF30F+a0Fv8Ed7kHbU40elc4SYOxXGJoxibmDl++D70W/AkeMvewX94VsEvjV57yQjrWhxNuTfsbW0lVlaynxHbw6AL4Jn9QSkdb4QIzQ4TfmIbsxP4zibxpmjE6vS33EfCjzEn+MFHrkuTikQsFZFJt07BxtvWSgVBXwX8MyQYU8xOcmObQ+cWLH6rpAANQy2RU3LKssX0tR2IfY7DsOrQbsM7VnHK5Kg04S69o8+J62HEpAfpbjMvBjcXkWrTw77jeyxq7qeqOUdH0J2u7pwNFsUbyF5cVNCAxkwPe4QfxORVKQXNsZRt+esJ5KvSpQ26hnKrQ0JBI5GLvLSSCntFLxl12x+NYDA5hqNJDnC/Dze4bPpgtt4o+Gxo8NGS10t9lOA6VCkEhViCByE4ur96C4j2BrVYDtWMHvvLHWIwJ8flTPEqp91dZie40Ng0ZbFIVKxCT+JqsEsscjSEYpUkyRpwy9p2+uR0pSfxqrYxFGnYxB6NDXCIzOKEDlHyCSkctQkEmpIJ1U8TxHj5L0kebb0fIwye3jQ5uH9PUiQIpxxoCnSSx49k5UMc6/ARiuBRgyrEC3AAAAAElFTkSuQmCC');\n                });\n\n                document.getElementById(\"paste-image-from\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"paste-image-to\");\n                });\n\n                ipcRenderer.on(\"paste-from\", (sender, text) => {\n                    const message = `Clipboard contents: ${text}`;\n                    document.getElementById(\"paste-from\").innerText = message;\n                });\n\n                ipcRenderer.on(\"paste-image-from\", (sender, data) => {\n                    console.log(data);\n                    var data = JSON.parse(data);\n                    const ni = nativeImage.createEmpty();\n                    for (var i in data) {\n                        var scaleFactor = i;\n                        var bytes = data[i];\n                        var buff = Buffer.from(bytes, 'base64');\n                        ni.addRepresentation({ scaleFactor: scaleFactor, buffer: buff });\n                    }\n\n                    document.getElementById(\"paste-image-from-div\").src = ni.toDataURL();\n                });\n\n\n                var PasteImage = function (el) {\n                    this._el = el;\n                    this._listenForPaste();\n                };\n\n                PasteImage.prototype._getURLObj = function () {\n                    return window.URL || window.webkitURL;\n                };\n\n                PasteImage.prototype._pasteImage = function (image) {\n                    this.emit('paste-image', image);\n                };\n\n                PasteImage.prototype._pasteImageSource = function (src) {\n                    var self = this,\n                        image = new Image();\n\n                    image.onload = function () {\n                        self._pasteImage(image);\n                    };\n\n                    image.src = src;\n                };\n\n                PasteImage.prototype._onPaste = function (e) {\n\n                    // We need to check if event.clipboardData is supported (Chrome & IE)\n                    if (e.clipboardData && e.clipboardData.items) {\n\n                        // Get the items from the clipboard\n                        var items = e.clipboardData.items;\n\n                        // Loop through all items, looking for any kind of image\n                        for (var i = 0; i < items.length; i++) {\n                            if (items[i].type.indexOf('image') !== -1) {\n                                // We need to represent the image as a file\n                                var blob = items[i].getAsFile();\n\n                                // Use a URL or webkitURL (whichever is available to the browser) to create a\n                                // temporary URL to the object\n                                var URLObj = this._getURLObj();\n                                var source = URLObj.createObjectURL(blob);\n\n                                // The URL can then be used as the source of an image\n                                this._pasteImageSource(source);\n\n                                // Prevent the image (or URL) from being pasted into the contenteditable element\n                                e.preventDefault();\n                            }\n                        }\n                    }\n                };\n\n                PasteImage.prototype._listenForPaste = function () {\n                    var self = this;\n\n                    self._origOnPaste = self._el.onpaste;\n\n                    self._el.addEventListener('paste', function (e) {\n\n                        self._onPaste(e);\n\n                        // Preserve an existing onpaste event handler\n                        if (self._origOnPaste) {\n                            self._origOnPaste.apply(this, arguments);\n                        }\n\n                    });\n                };\n\n                PasteImage.prototype.on = function (event, callback) {\n                    this._callback = callback;\n                };\n\n                PasteImage.prototype.emit = function (event, arg) {\n                    this._callback(arg);\n                };\n\n                var pasteImage = new PasteImage(document.getElementById('paste-image-div'));\n\n                pasteImage.on('paste-image', function (image) {\n                    document.getElementById('image-paste-div').appendChild(image);\n                });\n\n\n            }());\n        </script>\n\n    </section>\n</template>\n\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/CrashHang/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n  <section id=\"crash-hang-section\" class=\"section js-section u-category-windows\">\n    <header class=\"section-header\">\n      <div class=\"section-wrapper\">\n        <h1>\n          <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-windows\"></use></svg>\n          Handling Window Crashes and Hangs\n        </h1>\n        <h3>The <code>Electron.WindowManager</code> will emit events when the renderer process crashes or hangs. You can listen for these events and give users the chance to reload, wait or close that window.</h3>\n        \n        <p>You find the sample source code in <code>Controllers\\CrashHangController.cs</code>.</p>\n      </div>\n    </header>\n\n    <div class=\"demo\">\n      <div class=\"demo-wrapper\">\n        <button id=\"new-window-crashes-demo-toggle\" class=\"js-container-target demo-toggle-button\">Relaunch window after the process crashes\n          <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n        </button>\n        <div class=\"demo-box\">\n          <div class=\"demo-controls\">\n            <button class=\"demo-button\" id=\"process-crash\">View Demo</button>\n          </div>\n          <p>In this demo we create a new window and provide a link that will force a crash using <code>process.crash()</code>.</p>\n          <p>The window is listening for the crash event and when the event occurs it prompts the user with two options: reload or close.</p>\n\n          <h5>Main Process (C#)</h5>\n          <pre><code class=\"csharp\">var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);\nbrowserWindow.WebContents.OnCrashed += async (killed) => {\n    var options = new MessageBoxOptions(\"This process has crashed.\") {\n        Type = MessageBoxType.info,\n        Title = \"Renderer Process Crashed\",\n        Buttons = new string[] { \"Reload\", \"Close\" }\n    };\n    var result = await Electron.Dialog.ShowMessageBoxAsync(options);\n\n    if (result.Response == 0)\n    {\n        browserWindow.Reload();\n    } else\n    {\n        browserWindow.Close();\n    }\n};</code></pre>\n        </div>\n      </div>\n    </div>\n\n    <div class=\"demo\">\n      <div class=\"demo-wrapper\">\n        <button id=\"new-window-hangs-demo-toggle\" class=\"js-container-target demo-toggle-button\">Relaunch window after the process hangs\n          <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n        </button>\n        <div class=\"demo-box\">\n          <div class=\"demo-controls\">\n            <button class=\"demo-button\" id=\"process-hang\">View Demo</button>\n          </div>\n          <p>In this demo we create a new window and provide a link that will force the process to hang using <code>process.hang()</code>.</p>\n          <p>The window is listening for the process to become officially unresponsive (this can take up to 30 seconds). When this event occurs it prompts the user with two options: reload or close.</p>\n\n          <h5>Main Process (C#)</h5>\n          <pre><code class=\"csharp\">var browserWindow = await Electron.WindowManager.CreateWindowAsync();\nbrowserWindow.OnUnresponsive += async () => {\n    var options = new MessageBoxOptions(\"This process is hanging.\")\n    {\n        Type = MessageBoxType.info,\n        Title = \"Renderer Process Hanging\",\n        Buttons = new string[] { \"Reload\", \"Close\" }\n    };\n    var result = await Electron.Dialog.ShowMessageBoxAsync(options);\n\n    if (result.Response == 0)\n    {\n        browserWindow.Reload();\n    }\n    else\n    {\n        browserWindow.Close();\n    }\n};</code></pre>\n\n          <div class=\"demo-protip\">\n            <h2>ProTip</h2>\n            <strong>Wait for the process to become responsive again.</strong>\n            <p>A third option in the case of a process that is hanging is to wait and see if the problem resolves, allowing the process to become responsive again. To do this, use the <code>BrowserWindow</code> event 'OnResponsive' as shown below.</p>\n            <pre><code class=\"csharp\">browserWindow.OnResponsive += () =>\n{\n    // Do something when the window is responsive again\n};</code></pre>\n          </div>\n        </div>\n      </div>\n    </div>\n\n\n\n    <script type=\"text/javascript\">\n    (function(){\n      const { ipcRenderer } = require(\"electron\");\n      \n      document.getElementById(\"process-crash\").addEventListener(\"click\", () => {\n        ipcRenderer.send(\"process-crash\");\n        });\n\n      document.getElementById(\"process-hang\").addEventListener(\"click\", () => {\n        ipcRenderer.send(\"process-hang\");\n        });     \n\n      }());\n    </script>\n\n  </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/CrashHang/ProcessCrash.cshtml",
    "content": "﻿<style>\n    body {\n        padding: 20px;\n        font-family: system, -apple-system, '.SFNSText-Regular', 'SF UI Text', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif;\n        color: #fff;\n        background-color: #8aba87;\n        text-align: center;\n        font-size: 40px;\n    }\n\n    #crash {\n        color: white;\n        opacity: 0.7;\n        position: absolute;\n        bottom: 20px;\n        left: 50%;\n        transform: translateX(-50%);\n        font-size: 12px;\n        text-decoration: none;\n    }\n</style>\n\n<p>Click the text below to crash and then reload this process.</p>\n<a id=\"crash\" href=\"javascript:process.crash()\">Crash this process</a>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/CrashHang/ProcessHang.cshtml",
    "content": "﻿<style>\n    body {\n        padding: 20px;\n        font-family: system, -apple-system, '.SFNSText-Regular', 'SF UI Text', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif;\n        color: #fff;\n        background-color: #8aba87;\n        text-align: center;\n    }\n\n    p {\n        font-size: 32px;\n    }\n\n    #crash {\n        color: white;\n        opacity: 0.7;\n        position: absolute;\n        bottom: 20px;\n        left: 50%;\n        transform: translateX(-50%);\n        font-size: 12px;\n        text-decoration: none;\n    }\n</style>\n\n<p>Click the text below to hang and then reload this process.</p>\n<small>(This will take up to 30 seconds.)</small>\n\n<a id=\"crash\" href=\"javascript:process.hang()\">Hang this process</a>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/DesktopCapturer/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n  <section id=\"desktop-capturer-section\" class=\"section js-section u-category-media\">\n    <header class=\"section-header\">\n      <div class=\"section-wrapper\">\n        <h1>\n          <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-media\"></use></svg>\n          Take a screenshot\n        </h1>\n        <h3>The <code>desktopCapturer</code> module in Electron can be used to access any media, such as audio, video, screen and window, that is available through the <code>getUserMedia</code> web API in Chromium.</h3>\n\n        <p>Open the <a href=\"http://electron.atom.io/docs/api/desktop-capturer\">full API documentation<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a> in your browser.</p>\n      </div>\n    </header>\n\n    <div class=\"demo\">\n      <div class=\"demo-wrapper\">\n        <button id=\"print-pdf-demo-toggle\" class=\"js-container-target demo-toggle-button\">Take a Screenshot\n          <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux | Process: Renderer</div>\n        </button>\n        <div class=\"demo-box\">\n          <div class=\"demo-controls\">\n            <button class=\"demo-button\" id=\"screen-shot\">View Demo</button>\n            <span class=\"demo-response is-selectable\" id=\"screenshot-path\"></span>\n          </div>\n          <p>This demo uses the <code>desktopCapturer</code> module to gather screens in use and select the entire screen and take a snapshot of what is visible.</p>\n          <p>Clicking the demo button will take a screenshot of your current screen and open it in your default viewer.</p>\n          <h5>Renderer Process (JavaScript)</h5>\n          <pre><code class=\"javascript\">const electron = require('electron');\nconst desktopCapturer = electron.desktopCapturer;\nconst electronScreen = electron.screen;\nconst shell = electron.shell;\n\nconst fs = require('fs');\nconst os = require('os');\nconst path = require('path');\n\nconst screenshot = document.getElementById('screen-shot');\nconst screenshotMsg = document.getElementById('screenshot-path');\n\nscreenshot.addEventListener('click', function (event) {\n    screenshotMsg.textContent = 'Gathering screens...';\n    const thumbSize = determineScreenShotSize();\n    let options = { types: ['screen'], thumbnailSize: thumbSize }\n\n    desktopCapturer.getSources(options, function (error, sources) {\n        if (error) return console.log(error);\n\n        sources.forEach(function (source) {\n            if (source.name === 'Entire screen' || source.name === 'Screen 1') {\n                const screenshotPath = path.join(os.tmpdir(), 'screenshot.png');\n\n                fs.writeFile(screenshotPath, source.thumbnail.toPng(), function (error) {\n                if (error) return console.log(error);\n                shell.openExternal('file://' + screenshotPath);\n                const message = `Saved screenshot to: ${screenshotPath}`;\n                screenshotMsg.textContent = message;\n                });\n            }\n        })\n    })\n})\n\nfunction determineScreenShotSize () {\n    const screenSize = electronScreen.getPrimaryDisplay().workAreaSize;\n    const maxDimension = Math.max(screenSize.width, screenSize.height);\n    return {\n        width: maxDimension * window.devicePixelRatio,\n        height: maxDimension * window.devicePixelRatio\n    }\n}</code></pre>\n        </div>\n      </div>\n    </div>\n\n    <script type=\"text/javascript\">\n      (function(){\n          \n            const electron = require('electron');\n            const desktopCapturer = electron.desktopCapturer;\n            const electronScreen = electron.screen;\n            const shell = electron.shell;\n\n            const fs = require('fs');\n            const os = require('os');\n            const path = require('path');\n\n            const screenshot = document.getElementById('screen-shot');\n            const screenshotMsg = document.getElementById('screenshot-path');\n\n            screenshot.addEventListener('click', function (event) {\n                screenshotMsg.textContent = 'Gathering screens...';\n                const thumbSize = determineScreenShotSize();\n                let options = { types: ['screen'], thumbnailSize: thumbSize }\n\n                desktopCapturer.getSources(options, function (error, sources) {\n                    if (error) return console.log(error);\n\n                    sources.forEach(function (source) {\n                        if (source.name === 'Entire screen' || source.name === 'Screen 1') {\n                            const screenshotPath = path.join(os.tmpdir(), 'screenshot.png');\n\n                            fs.writeFile(screenshotPath, source.thumbnail.toPng(), function (error) {\n                            if (error) return console.log(error);\n                            shell.openExternal('file://' + screenshotPath);\n                            const message = `Saved screenshot to: ${screenshotPath}`;\n                            screenshotMsg.textContent = message;\n                            });\n                        }\n                    })\n                })\n            })\n\n            function determineScreenShotSize () {\n                const screenSize = electronScreen.getPrimaryDisplay().workAreaSize;\n                const maxDimension = Math.max(screenSize.width, screenSize.height);\n                return {\n                    width: maxDimension * window.devicePixelRatio,\n                    height: maxDimension * window.devicePixelRatio\n                }\n            }\n\n            }());\n    </script>\n\n  </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Dialogs/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"dialogs-section\" class=\"section js-section u-category-native-ui\">\n        <header class=\"section-header\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-native-ui\"></use></svg>\n                    Use system dialogs\n                </h1>\n                <h3>The <code>Electron.Dialog</code> in Electron.NET allows you to use native system dialogs for opening files or directories, saving a file or displaying informational messages.</h3>\n\n                <p>This is a main process module because this process is more efficient with native utilities and it allows the call to happen without interupting the visible elements in your page's renderer process.</p>\n\n                <p>You find the sample source code in <code>Controllers\\DialogsController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"open-file-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Open a File or Directory\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"select-directory\">View Demo</button>\n                        <span class=\"demo-response\" id=\"selected-file\"></span>\n                    </div>\n                    <p>In this demo, the <code>ipcRenderer</code> is used to send a message from the renderer process instructing the main process to launch the open file (or directory) dialog. If a file is selected, the main process can send that information back to the renderer process.</p>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"language-js\">const { ipcRenderer } = require(\"electron\");\n\ndocument.getElementById(\"select-directory\").addEventListener(\"click\", () => {\n    ipcRenderer.send(\"select-directory\");\n});\n\nipcRenderer.on(\"select-directory-reply\", (sender, path) => {\n    document.getElementById(\"selected-file\").innerText = `You selected: ${path}`;;\n});</code></pre>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"select-directory\", async (args) => {\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    var options = new OpenDialogOptions {\n        Properties = new OpenDialogProperty[] {\n            OpenDialogProperty.openFile,\n            OpenDialogProperty.openDirectory\n        }\n    };\n\n    string[] files = await Electron.Dialog.ShowOpenDialogAsync(mainWindow, options);\n    Electron.IpcMain.Send(mainWindow, \"select-directory-reply\", files);\n});</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"error-dialog-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Error Dialog\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button id=\"error-dialog\" class=\"demo-button\">View Demo</button>\n                    </div>\n                    <p>In this demo, the <code>ipcRenderer</code> is used to send a message from the renderer process instructing the main process to launch the error dialog.</p>\n\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"language-js\">const { ipcRenderer } = require(\"electron\");\n\ndocument.getElementById(\"error-dialog\").addEventListener(\"click\", () => {\n    ipcRenderer.send(\"error-dialog\");\n});</code></pre>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"error-dialog\", (args) =>\n{\n    Electron.Dialog.ShowErrorBox(\"An Error Message\", \"Demonstrating an error message.\");\n});</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"information-dialog-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Information Dialog\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"information-dialog\">View Demo</button>\n                        <span class=\"demo-response\" id=\"info-selection\"></span>\n                    </div>\n                    <p>In this demo, the <code>ipcRenderer</code> is used to send a message from the renderer process instructing the main process to launch the information dialog. Options may be provided for responses which can then be relayed back to the renderer process.</p>\n\n                    <p>Note: The <code>title</code> property is not displayed in macOS.</p>\n\n                    <p>An information dialog can contain an icon, your choice of buttons, title and message.</p>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"javascript\">document.getElementById(\"information-dialog\").addEventListener(\"click\", () => {\n    ipcRenderer.send(\"information-dialog\");\n});\n\nipcRenderer.on(\"information-dialog-reply\", (sender, index) => {\n    let message = 'You selected ';\n\n    if(index == 0) {\n        message += 'yes.'\n    } else {\n        message += 'no.'\n    }\n\n    document.getElementById(\"info-selection\").innerText = message;\n});</code></pre>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"information-dialog\", async (args) =>\n{\n    var options = new MessageBoxOptions(\"This is an information dialog. Isn't it nice?\")\n    {\n        Type = MessageBoxType.info,\n        Title = \"Information\",\n        Buttons = new string[] { \"Yes\", \"No\" }\n    };\n\n    var result = await Electron.Dialog.ShowMessageBoxAsync(options);\n\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    Electron.IpcMain.Send(mainWindow, \"information-dialog-reply\", result.Response);\n});</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"save-dialog-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Save Dialog\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"save-dialog\">View Demo</button>\n                        <span class=\"demo-response\" id=\"file-saved\"></span>\n                    </div>\n                    <p>In this demo, the <code>ipcRenderer</code> is used to send a message from the renderer process instructing the main process to launch the save dialog. It returns the path selected by the user which can be relayed back to the renderer process.</p>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"javascript\">const { ipcRenderer } = require(\"electron\");\n\ndocument.getElementById(\"save-dialog\").addEventListener(\"click\", () => {\n    ipcRenderer.send(\"save-dialog\");\n});\n\nipcRenderer.on(\"save-dialog-reply\", (sender, path) => {\n    if (!path) path = 'No path';\n    document.getElementById('file-saved').innerHTML = `Path selected: ${path}`;\n});</code></pre>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"save-dialog\", async (args) =>\n{\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    var options = new SaveDialogOptions\n    {\n        Title = \"Save an Image\",\n        Filters = new FileFilter[]\n        {\n            new FileFilter { Name = \"Images\", Extensions = new string[] {\"jpg\", \"png\", \"gif\" } }\n        }\n    };\n\n    var result = await Electron.Dialog.ShowSaveDialogAsync(mainWindow, options);\n    Electron.IpcMain.Send(mainWindow, \"save-dialog-reply\", result);\n});</code></pre>\n                </div>\n            </div>\n        </div>\n        \n        <script>\n            (function(){\n                const { ipcRenderer } = require(\"electron\");\n                \n                document.getElementById(\"select-directory\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"select-directory\");\n                });\n                \n                ipcRenderer.on(\"select-directory-reply\", (sender, path) => {\n                    document.getElementById(\"selected-file\").innerText = `You selected: ${path}`;\n                });\n                \n                document.getElementById(\"error-dialog\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"error-dialog\");\n                });\n\n                document.getElementById(\"information-dialog\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"information-dialog\");\n                });\n\n                ipcRenderer.on(\"information-dialog-reply\", (sender, index) => {\n                    let message = 'You selected ';\n\n                    if(index == 0) {\n                        message += 'yes.'\n                    } else {\n                        message += 'no.'\n                    }\n\n                    document.getElementById(\"info-selection\").innerText = message;\n                });\n\n                document.getElementById(\"save-dialog\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"save-dialog\");\n                });\n\n                ipcRenderer.on(\"save-dialog-reply\", (sender, path) => {\n                    if (!path) path = 'No path';\n                    document.getElementById('file-saved').innerHTML = `Path selected: ${path}`;\n                });\n               \n            }());\n        </script>\n\n    </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Home/Index.cshtml",
    "content": "﻿<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <link rel=\"stylesheet\" href=\"assets/css/variables.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/nativize.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/global.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/about.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/nav.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/section.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/demo.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/github.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/highlight.min.css\">\n</head>\n<body>\n\n    <nav class=\"nav js-nav\">\n        <header class=\"nav-header\">\n            <h1 class=\"nav-title\">Electron.NET <strong>API Demos</strong></h1>\n        </header>\n\n        <div class=\"nav-item u-category-windows\">\n            <h5 class=\"nav-category\">\n                <svg class=\"nav-icon\"><use xlink:href=\"assets/img/icons.svg#icon-windows\"></use></svg>\n                Windows\n            </h5>\n            <button type=\"button\" id=\"button-windows\" data-section=\"windows\" class=\"nav-button\">Create and manage <em>windows</em></button>\n            <button type=\"button\" id=\"button-crash-hang\" data-section=\"crash-hang\" class=\"nav-button\">Handling window <em>crashes and hangs</em></button>\n        </div>\n\n        <div class=\"nav-item u-category-menu\">\n            <h5 class=\"nav-category\">\n                <svg class=\"nav-icon\"><use xlink:href=\"assets/img/icons.svg#icon-menu\"></use></svg>\n                Menus\n            </h5>\n            <button type=\"button\" id=\"button-menus\" data-section=\"menus\" class=\"nav-button\">Customize <em>menus</em> </button>\n            <button type=\"button\" id=\"button-shortcuts\" data-section=\"shortcuts\" class=\"nav-button\">Register keyboard <em>shortcuts</em></button>\n        </div>\n\n        <div class=\"nav-item u-category-native-ui\">\n            <h5 class=\"nav-category\">\n                <svg class=\"nav-icon\"><use xlink:href=\"assets/img/icons.svg#icon-native-ui\"></use></svg>\n                Native User Interface\n            </h5>\n            <button type=\"button\" id=\"button-ex-links-file-manager\" data-section=\"ex-links-file-manager\" class=\"nav-button\">Open <em>external links</em> or system <em>file manager</em></button>\n            <button type=\"button\" id=\"button-notifications\" data-section=\"notifications\" class=\"nav-button\"> Notifications with and without custom <em>image</em></button>\n            <button type=\"button\" id=\"button-dialogs\" data-section=\"dialogs\" class=\"nav-button\">Use system <em>dialogs</em></button>\n            <button type=\"button\" id=\"button-tray\" data-section=\"tray\" class=\"nav-button\">Put your app in the <em>tray</em></button>\n        </div>\n\n        <div class=\"nav-item u-category-communication\">\n            <h5 class=\"nav-category\">\n                <svg class=\"nav-icon\"><use xlink:href=\"assets/img/icons.svg#icon-communication\"></use></svg>\n                Communication\n            </h5>\n            <button type=\"button\" id=\"button-ipc\" data-section=\"ipc\" class=\"nav-button\">Communicate between the <em>two processes</em></button>\n            <button type=\"button\" id=\"button-hosthook\" data-section=\"hosthook\" class=\"nav-button\">Execute your own <em>TypeScript code</em></button>\n        </div>\n\n        <div class=\"nav-item u-category-system\">\n            <h5 class=\"nav-category\">\n                <svg class=\"nav-icon\"><use xlink:href=\"assets/img/icons.svg#icon-system\"></use></svg>\n                System\n            </h5>\n            <button type=\"button\" id=\"button-app-sys-information\" data-section=\"app-sys-information\" class=\"nav-button\">Get app or user <em>system information</em></button>\n            <button type=\"button\" id=\"button-clipboard\" data-section=\"clipboard\" class=\"nav-button\">Copy and paste from the <em>clipboard</em></button>\n            <!-- <button type=\"button\" id=\"button-protocol\" data-section=\"protocol\" class=\"nav-button\">Launch app from <em>protocol handler</em></button> -->\n        </div>\n\n        <div class=\"nav-item u-category-update\">\n            <h5 class=\"nav-category\">\n                <svg class=\"nav-icon\"><use xlink:href=\"assets/img/icons.svg#icon-update\"></use></svg>\n                Update\n            </h5>\n            <button type=\"button\" id=\"button-update\" data-section=\"update\" class=\"nav-button\">Enable apps to <em>update</em> themselves\n            </button>\n        </div>\n\n        <div class=\"nav-item u-category-media\">\n            <h5 class=\"nav-category\">\n                <svg class=\"nav-icon\"><use xlink:href=\"assets/img/icons.svg#icon-media\"></use></svg>\n                Media\n            </h5>\n            <button type=\"button\" id=\"button-pdf\" data-section=\"pdf\" class=\"nav-button\"><em>Print</em> to PDF</button>\n            <button type=\"button\" id=\"button-desktop-capturer\" data-section=\"desktop-capturer\" class=\"nav-button\">Take a <em>screenshot</em></button>\n        </div>\n\n        <footer class=\"nav-footer\">\n            <button type=\"button\" id=\"button-about\" data-modal=\"about\" class=\"nav-footer-button\">About</button>\n            <a class=\"nav-footer-logo\" href=\"https://github.com/ElectronNET/Electron.NET\" aria-label=\"Homepage\" target=\"_blank\">\n                Made with <img src=\"assets/img/heart.jpg\" style=\"width:14px;\" /> in C#\n            </a>\n        </footer>\n    </nav>\n\n    <main class=\"content js-content is-shown\"></main>\n\n    <script src=\"~/assets/imports.js\"></script>\n    <script src=\"~/assets/ex-links.js\"></script>\n    <script src=\"~/assets/nav.js\"></script>\n    <script src=\"~/assets/demo-btns.js\"></script>\n    <script src=\"~/assets/highlight.min.js\"></script>\n    <script src=\"~/assets/code-blocks.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/HostHook/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"hosthook-section\" class=\"section js-section u-category-communication\">\n        <header class=\"communication\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-communication\"></use></svg>\n                    Execute your own TypeScript code\n                </h1>\n                <h3>The <code>HostHook</code> API allows you to execute your own JavaScript/TypeScript code on the host process.</h3>\n\n                <p>Create first an ElectronHostHook directory via the Electron.NET CLI, with the following command: <code>electronize add hosthook</code>.</p>\n                <p>In this directory you can install any NPM packages and embed your own JavaScript/TypeScript code. It is also possible to respond to events from the host process.</p>\n                <p>You find the sample source code in <code>Controllers\\HostHookController.cs</code> and in the <code>ElectronHostHook</code> folder.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"async-msg-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Execute TypeScript code\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"start-hoosthook-button\">Create Excel-File</button>\n                        <span class=\"demo-response\" id=\"hoosthook-reply\"></span>\n                    </div>\n                    <p>Use <code>Electron.HostHook.CallAsync</code> to execute asynchronously your own JavaScript/TypeScript code, that expect a result value.</p>\n\n                    <p>This example execute the TypeScript code, that listening on \"create-excel\". The TypeScript code use a NPM Package names exceljs, to create a Excel file and reply a success message.</p>\n\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"start-hoosthook\", async (args) =>\n{\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    var options = new OpenDialogOptions\n    {\n        Properties = new OpenDialogProperty[]\n        {\n            OpenDialogProperty.openDirectory\n        }\n    };\n    var folderPath = await Electron.Dialog.ShowOpenDialogAsync(mainWindow, options);\n\n    var resultFromTypeScript = await Electron.HostHook.CallAsync&lt;string&gt;(\"create-excel-file\", folderPath);\n    Electron.IpcMain.Send(mainWindow, \"excel-file-created\", resultFromTypeScript);\n});</code>\n                    </pre>\n                    <h5>index.ts from ElectronHostHook-Folder (TypeScript)</h5>\n                    <pre>\n                        <code class=\"typescript\">import * as Electron from \"electron\";\nimport { Connector } from \"./connector\";\nimport { ExcelCreator } from \"./excelCreator\";\n\nexport class HookService extends Connector {\n    constructor(socket: SocketIO.Socket, public app: Electron.App) {\n        super(socket, app);\n    }\n\n    onHostReady(): void {\n        // execute your own JavaScript Host logic here\n        this.on(\"create-excel\", async (path, done) => {\n            const excelCreator: ExcelCreator = new ExcelCreator();\n            const result: string = await excelCreator.create(path);\n\n            done(result);\n        });\n    }\n}</code>\n                    </pre>\n                </div>\n            </div>\n        </div>\n\n        <script>\n            (function(){\n                const { ipcRenderer } = require(\"electron\");\n\n                document.getElementById(\"start-hoosthook-button\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"start-hoosthook\");\n                });\n\n                ipcRenderer.on('excel-file-created', (event, arg) => {\n                    const message = `Asynchronous message reply: ${arg}`;\n                    document.getElementById('hoosthook-reply').innerHTML = message;\n                });\n            }());\n        </script>\n\n    </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Ipc/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"ipc-section\" class=\"section js-section u-category-communication\">\n        <header class=\"communication\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-communication\"></use></svg>\n                    Communication between processes\n                </h1>\n                <h3>The <code>ipc</code> (inter-process communication) module allows you to send and receive synchronous and asynchronous messages between the main and renderer processes.</h3>\n\n                <p>There is a version of this module available for both processes: <code>Electron.IpcMain</code> and <code>ipcRenderer</code>.</p>\n                <p>You find the sample source code in <code>Controllers\\IpcController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"async-msg-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Asynchronous messages\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"async-msg\">Ping</button>\n                        <span class=\"demo-response\" id=\"async-reply\"></span>\n                    </div>\n                    <p>Using <code>ipcRenderer</code> to send messages between processes asynchronously is the preferred method since it will return when finished without blocking other operations in the same process.</p>\n\n                    <p>This example sends a \"ping\" from this process (renderer) to the main process. The main process then replies with \"pong\".</p>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"javascript\">const { ipcRenderer } = require(\"electron\");\n\ndocument.getElementById(\"async-msg\").addEventListener(\"click\", () => {\n    ipcRenderer.send(\"async-msg\", 'ping');\n});\n\nipcRenderer.on('asynchronous-reply', (event, arg) => {\n    const message = `Asynchronous message reply: ${arg}`;\n    document.getElementById('async-reply').innerHTML = message;\n});</code></pre>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"async-msg\", (args) =>\n{\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    Electron.IpcMain.Send(mainWindow, \"asynchronous-reply\", \"pong\");\n});</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"sync-msg-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Synchronous messages\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"sync-msg\">Ping</button>\n                        <span class=\"demo-response\" id=\"sync-reply\"></span>\n                    </div>\n                    <p>You can use the <code>ipcRenderer</code> module to send synchronous messages between processes as well, but note that the synchronous nature of this method means that it <b>will block</b> other operations while completing its task.</p>\n                    <p>This example sends a synchronous message, \"ping\", from this process (renderer) to the main process. The main process then replies with \"pong\".</p>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"javascript\">const { ipcRenderer } = require(\"electron\");\n\ndocument.getElementById(\"sync-msg\").addEventListener(\"click\", () => {\n    const reply = ipcRenderer.sendSync(\"sync-msg\", \"ping\");\n    const message = `Synchronous message reply: ${reply}`;\n    document.getElementById('sync-reply').innerHTML = message;\n});</code></pre>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.OnSync(\"sync-msg\", (args) =>\n{\n    return \"pong\";\n});</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <script>\n            (function(){\n                const { ipcRenderer } = require(\"electron\");\n\n                document.getElementById(\"async-msg\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"async-msg\", 'ping');\n                });\n\n                ipcRenderer.on('asynchronous-reply', (event, arg) => {\n                    const message = `Asynchronous message reply: ${arg}`;\n                    document.getElementById('async-reply').innerHTML = message;\n                });\n\n                document.getElementById(\"sync-msg\").addEventListener(\"click\", () => {\n                    const reply = ipcRenderer.sendSync(\"sync-msg\", \"ping\");\n                    const message = `Synchronous message reply: ${reply}`;\n                    document.getElementById('sync-reply').innerHTML = message;\n                });\n\n            }());\n        </script>\n\n    </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Menus/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"menus-section\" class=\"section js-section u-category-menu\">\n        <header class=\"section-header\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-menu\"></use></svg>\n                    Customize Menus\n                </h1>\n                <h3>The <code>Electron.Menu</code> and <code>MenuItem</code> can be used to create custom native menus.</h3>\n\n                <p>There are two kinds of menus: the application (top) menu and context (right-click) menu.</p>\n\n                <p>You find the sample source code in <code>Controllers\\MenusController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"application-menu-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Create an application menu\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <p>The <code>Electron.Menu</code> and <code>MenuItem</code> allow you to customize your application menu. If you don't set any menu, Electron will generate a minimal menu for your app by default.</p>\n\n                    <p>This app uses the code below to set the application menu. If you click the 'View' option in the application menu and then the 'App Menu Demo', you'll see an information box displayed.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">var menu = new MenuItem[] {\n    new MenuItem { Label = \"Edit\", Submenu = new MenuItem[] {\n        new MenuItem { Label = \"Undo\", Accelerator = \"CmdOrCtrl+Z\", Role = MenuRole.undo },\n        new MenuItem { Label = \"Redo\", Accelerator = \"Shift+CmdOrCtrl+Z\", Role = MenuRole.redo },\n        new MenuItem { Type = MenuType.separator },\n        new MenuItem { Label = \"Cut\", Accelerator = \"CmdOrCtrl+X\", Role = MenuRole.cut },\n        new MenuItem { Label = \"Copy\", Accelerator = \"CmdOrCtrl+C\", Role = MenuRole.copy },\n        new MenuItem { Label = \"Paste\", Accelerator = \"CmdOrCtrl+V\", Role = MenuRole.paste },\n        new MenuItem { Label = \"Select All\", Accelerator = \"CmdOrCtrl+A\", Role = MenuRole.selectall }\n    }\n    },\n    new MenuItem { Label = \"View\", Submenu = new MenuItem[] {\n        new MenuItem\n        {\n            Label = \"Reload\",\n            Accelerator = \"CmdOrCtrl+R\",\n            Click = () =>\n            {\n                // on reload, start fresh and close any old\n                // open secondary windows\n                Electron.WindowManager.BrowserWindows.ToList().ForEach(browserWindow => {\n                    if(browserWindow.Id != 1)\n                    {\n                        browserWindow.Close();\n                    }\n                    else\n                    {\n                        browserWindow.Reload();\n                    }\n                });\n            }\n        },\n        new MenuItem\n        {\n            Label = \"Toggle Full Screen\",\n            Accelerator = \"CmdOrCtrl+F\",\n            Click = async () =>\n            {\n                bool isFullScreen = await Electron.WindowManager.BrowserWindows.First().IsFullScreenAsync();\n                Electron.WindowManager.BrowserWindows.First().SetFullScreen(!isFullScreen);\n            }\n        },\n        new MenuItem\n        {\n            Label = \"Open Developer Tools\",\n            Accelerator = \"CmdOrCtrl+I\",\n            Click = () => Electron.WindowManager.BrowserWindows.First().WebContents.OpenDevTools()\n        },\n        new MenuItem\n        {\n            Type = MenuType.separator\n        },\n        new MenuItem\n        {\n            Label = \"App Menu Demo\",\n            Click = async () => {\n                var options = new MessageBoxOptions(\"This demo is for the Menu section, showing how to create a clickable menu item in the application menu.\");\n                options.Type = MessageBoxType.info;\n                options.Title = \"Application Menu Demo\";\n                await Electron.Dialog.ShowMessageBoxAsync(options);\n            }\n        }\n    }\n    },\n    new MenuItem { Label = \"Window\", Role = MenuRole.window, Submenu = new MenuItem[] {\n            new MenuItem { Label = \"Minimize\", Accelerator = \"CmdOrCtrl+M\", Role = MenuRole.minimize },\n            new MenuItem { Label = \"Close\", Accelerator = \"CmdOrCtrl+W\", Role = MenuRole.close }\n    }\n    },\n    new MenuItem { Label = \"Help\", Role = MenuRole.help, Submenu = new MenuItem[] {\n        new MenuItem \n        { \n            Label = \"Learn More\",\n            Click = async () => await Electron.Shell.OpenExternalAsync(\"https://github.com/ElectronNET\")\n        }\n    }\n    }\n};\n\nElectron.Menu.SetApplicationMenu(menu);</code></pre>\n\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Know operating system menu differences.</strong>\n                        <p>When designing an app for multiple operating systems it's important to be mindful of the ways application menu conventions differ on each operating system.</p>\n                        <p>For instance, on Windows, accelerators are set with an <code>&</code>. Naming conventions also vary, like between \"Settings\" or \"Preferences\". Below are resources for learning operating system specific standards.</p>\n                        <ul>\n                            <li><a href=\"https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/MenuBarMenus.html#//apple_ref/doc/uid/20000957-CH29-SW1\">macOS<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a></li>\n                            <li><a href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/bb226797(v=vs.85).aspx\">Windows<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a></li>\n                            <li><a href=\"https://developer.gnome.org/hig/stable/menu-bars.html.en\">Linux<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a></li>\n                        </ul>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"context-menu-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Create a context menu\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"context-menu\">View Demo</button>\n                    </div>\n                    <p>A context, or right-click, menu can be created with the <code>Electron.Menu.SetContextMenu()</code> and <code>MenuItem</code> as well. You can right-click anywhere in this app or click the demo button to see an example context menu.</p>\n\n                    <p>In this demo we use the <code>ipcRenderer</code> module to show the context menu when explicitly calling it from the renderer process.</p>\n                    <p>See the full <a href=\"http://electron.atom.io/docs/api/web-contents/#event-context-menu\">context-menu event documentation</a> for all the available properties.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">var menu = new MenuItem[]\n{\n    new MenuItem\n    {\n        Label = \"Hello\",\n        Click = async () => await Electron.Dialog.ShowMessageBoxAsync(\"Electron.NET rocks!\")\n    },\n    new MenuItem { Type = MenuType.separator },\n    new MenuItem { Label = \"Electron.NET\", Type = MenuType.checkbox, Checked = true }\n};\n\nvar mainWindow = Electron.WindowManager.BrowserWindows.First();\nElectron.Menu.SetContextMenu(mainWindow, menu);\n\nElectron.IpcMain.On(\"show-context-menu\", (args) => {\n    Electron.Menu.ContextMenuPopup(mainWindow);\n});</code></pre>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"javascript\">const { ipcRenderer } = require(\"electron\");\n\nwindow.addEventListener('contextmenu', (e) => {\n    e.preventDefault()\n    ipcRenderer.send('show-context-menu');\n}, false);</code></pre>\n                </div>\n            </div>\n        </div>\n\n    <script type=\"text/javascript\">\n    (function(){\n        const { ipcRenderer } = require(\"electron\");\n\n        const contextMenuBtn = document.getElementById('context-menu')\n        contextMenuBtn.addEventListener('click', function () {\n            ipcRenderer.send('show-context-menu');\n        })\n\n        window.addEventListener('contextmenu', (e) => {\n            e.preventDefault()\n            ipcRenderer.send('show-context-menu');\n        }, false);\n\n      }());\n    </script>\n\n    </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Notifications/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n  <section id=\"notifications-section\" class=\"section js-section u-category-native-ui\">\n    <header class=\"notifications\">\n      <div class=\"section-wrapper\">\n        <h1>\n          <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-notification\"></use></svg>\n          Desktop notifications\n        </h1>\n        <h3>The <code>Electron.Notification</code> in Electron.NET allows you to add basic desktop notifications.</h3>\n\n        <p>Electron conveniently allows developers to send notifications with the <a href=\"https://notifications.spec.whatwg.org/\">HTML5 Notification API</a>, using the currently running operating system’s native notification APIs to display it.</p>\n\n        <p><b>Note:</b> Since this is an HTML5 API it is only available in the renderer process.</p>\n        \n        <p>You find the sample source code in <code>Controllers\\NotificationsController.cs</code>.</p>\n      </div>\n    </header>\n\n    <div class=\"demo\">\n      <div class=\"demo-wrapper\">\n        <button id=\"basic-notification-demo-toggle\" class=\"js-container-target demo-toggle-button\">Basic notification\n          <div class=\"demo-meta u-avoid-clicks\">Supports: Win 7+, macOS, Linux (that supports libnotify)<span class=\"demo-meta-divider\">|</span> Process: Renderer</div>\n        </button>\n        <div class=\"demo-box\">\n          <div class=\"demo-controls\">\n            <button class=\"demo-button\" id=\"basic-noti\">View demo</button>\n          </div>\n          <p>This demo demonstrates a basic notification. Text only.</p>\n          <h5>Main Process (C#)</h5>\n          <pre><code class=\"csharp\">var options = new NotificationOptions(\"Basic Notification\", \"Short message part\")\n{\n    OnClick = async () => await Electron.Dialog.ShowMessageBoxAsync(\"Notification clicked\")\n};\n\nElectron.Notification.Show(options);</code></pre>\n        </div>\n      </div>\n    </div>\n\n    <div class=\"demo\">\n      <div class=\"demo-wrapper\">\n        <button id=\"advanced-notification-demo-toggle\" class=\"js-container-target demo-toggle-button\">Notification with image\n          <div class=\"demo-meta u-avoid-clicks\">Supports: Win 7+, macOS, Linux (that supports libnotify) <span class=\"demo-meta-divider\">|</span> Process: Renderer</div>\n        </button>\n        <div class=\"demo-box\">\n          <div class=\"demo-controls\">\n            <button class=\"demo-button\" id=\"advanced-noti\">View demo</button>\n          </div>\n          <p>This demo demonstrates a basic notification. Both text and a image</p>\n          <h5>Main Process (C#)</h5>\n          <pre><code class=\"csharp\">var options = new NotificationOptions(\"Notification with image\", \"Short message plus a custom image\")\n{\n    OnClick = async () => await Electron.Dialog.ShowMessageBoxAsync(\"Notification clicked\"),\n    Icon = \"/assets/img/programming.png\"\n};\n\nElectron.Notification.Show(options);</code></pre>\n        </div>\n      </div>\n    </div>\n\n<script type=\"text/javascript\">\n    (function(){\n        const { ipcRenderer } = require(\"electron\");\n        \n        document.getElementById(\"basic-noti\").addEventListener(\"click\", () => {\n            ipcRenderer.send(\"basic-noti\");\n        });\n        \n        document.getElementById(\"advanced-noti\").addEventListener(\"click\", () => {\n            ipcRenderer.send(\"advanced-noti\");\n        });\n\n      }());\n    </script>\n\n  </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Pdf/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"pdf-section\" class=\"section js-section u-category-media\">\n        <header class=\"section-header\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-media\"></use></svg>\n                    Print to PDF\n                </h1>\n                <h3>The <code>BrowserWindow</code> class in Electron.NET has a property, <code>WebContents</code>, which allows your app to print as well as print to PDF.</h3>\n\n                <p>You find the sample source code in <code>Controllers\\PdfController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"print-pdf-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Print to PDF\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"print-pdf\">View Demo</button>\n                        <span class=\"demo-response is-selectable\" id=\"pdf-path\"></span>\n                    </div>\n                    <p>To demonstrate the print to PDF functionality, the demo button above will save this page as a PDF and, if you have a PDF viewer, open the file.</p>\n                    <p>In a real-world application you're more likely to add this to application menu, but for the purposes of the demo we've set it to the demo button.</p>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"javascript\">const { ipcRenderer } = require(\"electron\");\n\ndocument.getElementById(\"print-pdf\").addEventListener(\"click\", () => {\n    ipcRenderer.send(\"print-pdf\");\n});</code></pre>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"print-pdf\", async (args) => {\n    BrowserWindow mainWindow = Electron.WindowManager.BrowserWindows.First();\n\n    var saveOptions = new SaveDialogOptions\n    {\n        Title = \"Save an PDF-File\",\n        DefaultPath = await Electron.App.GetPathAsync(PathName.documents),\n        Filters = new FileFilter[] \n        {\n            new FileFilter { Name = \"PDF\", Extensions = new string[] { \"pdf\" } }\n        }\n    };\n    var path = await Electron.Dialog.ShowSaveDialogAsync(mainWindow, saveOptions);\n\n    if (await mainWindow.WebContents.PrintToPDFAsync(path))\n    {\n        await Electron.Shell.OpenExternalAsync(\"file://\" + path);\n    }\n    else\n    {\n        Electron.Dialog.ShowErrorBox(\"Error\", \"Failed to create pdf file.\");\n    }\n});</code></pre>\n\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Use a print style sheet.</strong>\n                        <p>You can create a stylesheet targeting printing to optimize the look of what your users print. Below is the stylesheet used in this app, located in <code>assets/css/print.css</code>.</p>\n                    </div>\n                </div>\n            </div>\n        </div>\n        \n        <script>\n            (function(){\n                const { ipcRenderer } = require(\"electron\");\n\n                document.getElementById(\"print-pdf\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"print-pdf\");\n                });\n            }());\n        </script>\n\n    </section>\n</template>"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Shell/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"ex-links-file-manager-section\" class=\"section js-section u-category-native-ui\">\n        <header class=\"section-header\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-native-ui\"></use></svg>\n                    Open external links and the file manager\n                </h1>\n                <h3>The <code>Electron.Shell</code> in Electron.NET allows you to access certain native elements like the file manager and default web browser.</h3>\n\n                <p>This module works in both the main and renderer process.</p>\n                \n                <p>You find the sample source code in <code>Controllers\\ShellController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"open-file-manager-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Open Path in File Manager\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"open-file-manager\">View Demo</button>\n                    </div>\n                    <p>This demonstrates using the <code>Electron.Shell</code> to open the system file manager at a particular location.</p>\n                    <p>Clicking the demo button will open your file manager at the root.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">string path = await Electron.App.GetPathAsync(PathName.home);\nawait Electron.Shell.ShowItemInFolderAsync(path);</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"open-ex-links-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Open External Links\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Both</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"open-ex-links\">View Demo</button>\n                    </div>\n                    <p>If you do not want your app to open website links <em>within</em> the app, you can use the <code>Electron.Shell</code> to open them externally. When clicked, the links will open outside of your app and in the user's default web browser.</p>\n                    <p>When the demo button is clicked, the electron website will open in your browser.<p>\n                        <h5>Main Process (C#)</h5>\n                        <pre><code class=\"csharp\">await Electron.Shell.OpenExternalAsync(\"https://github.com/ElectronNET\");</code></pre>\n            </div>\n        </div>\n        </div>\n        \n        <script>\n            (function(){\n                const { ipcRenderer } = require(\"electron\");\n                \n                document.getElementById(\"open-file-manager\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"open-file-manager\");\n                });\n\n                document.getElementById(\"open-ex-links\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"open-ex-links\");\n                });\n\n            }());\n        </script>\n\n\n    </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Shortcuts/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n  <section id=\"shortcuts-section\" class=\"section js-section u-category-menu\">\n    <header class=\"section-header\">\n      <div class=\"section-wrapper\">\n        <h1>\n          <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-menu\"></use></svg>\n          Keyboard Shortcuts\n        </h1>\n\n        <h3>The <code>Electron.GlobalShortcut</code> and <code>MenuItem</code> can be used to define keyboard shortcuts.</h3>\n\n        <p>\n          In Electron.NET, keyboard shortcuts are called accelerators.\n          They can be assigned to actions in your application's Menu,\n          or they can be assigned globally so they'll be triggered even when\n          your app doesn't have keyboard focus.\n        </p>\n        \n        <p>You find the sample source code in <code>Controllers\\ShortcutsController.cs</code>.</p>\n\n      </div>\n    </header>\n\n    <div class=\"demo\">\n      <div class=\"demo-wrapper\">\n        <button id=\"shortcuts-demo-toggle\" class=\"js-container-target demo-toggle-button\">Register a global keyboard shortcut\n          <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n        </button>\n        <div class=\"demo-box\">\n          <p>\n            To try this demo, press <kbd class=\"normalize-to-platform\">CommandOrControl+Alt+K</kbd> on your keyboard.\n          </p>\n\n          <p>\n            Global shortcuts are detected even when the app doesn't have\n            keyboard focus.\n          </p>\n\n          <h5>Main Process (C#)</h5>\n          <pre><code class=\"csharp\">Electron.GlobalShortcut.Register(\"CommandOrControl+Alt+K\", async () => {\n    var options = new MessageBoxOptions(\"You pressed the registered global shortcut keybinding.\")\n    {\n        Type = MessageBoxType.info,\n        Title = \"Success!\"\n    };\n\n    await Electron.Dialog.ShowMessageBoxAsync(options);\n});\n\nElectron.App.WillQuit += (args) => Task.Run(() => Electron.GlobalShortcut.UnregisterAll());</code></pre>\n\n          <div class=\"demo-protip\">\n            <h2>ProTip</h2>\n            <strong>Avoid overriding system-wide keyboard shortcuts.</strong>\n            <p>\n              When registering global shortcuts, it's important to be aware of\n              existing defaults in the target operating system, so as not to\n              override any existing behaviors. For an overview of each\n              operating system's keyboard shortcuts, view these documents:\n            </p>\n\n            <ul>\n              <li><a class=\"u-exlink\" href=\"https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/Keyboard.html\">macOS</a></li>\n              <li><a class=\"u-exlink\" href=\"http://windows.microsoft.com/en-us/windows-10/keyboard-shortcuts\">Windows</a></li>\n              <li><a class=\"u-exlink\" href=\"https://developer.gnome.org/hig/stable/keyboard-input.html.en\">Linux</a></li>\n            </ul>\n          </div>\n\n        </div>\n      </div>\n    </div>\n\n  </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Tray/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"tray-section\" class=\"section js-section u-category-native-ui\">\n        <header class=\"section-header\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-native-ui\"></use></svg>\n                    Tray\n                </h1>\n                <h3>The <code>Electron.Tray</code> allows you to create an icon in the operating system's notification area.</h3>\n                <p>This icon can also have a context menu attached.</p>\n\n                <p>You find the sample source code in <code>Controllers\\TrayController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"tray-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Tray\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux | Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"put-in-tray\">View Demo</button>\n                        <span class=\"demo-response\" id=\"tray-countdown\"></span>\n                    </div>\n                    <p>The demo button sends a message to the main process using the <code>ipcRenderer</code>. In the main process the app is told to place an icon, with a context menu, in the tray.</p>\n\n                    <p>In this example the tray icon can be removed by clicking 'Remove' in the context menu or selecting the demo button again.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"put-in-tray\", (args) => {\n\n    if (Electron.Tray.Items.Count == 0)\n    {\n        var menu = new MenuItem\n        {\n            Label = \"Remove\",\n            Click = () => Electron.Tray.Destroy()\n        };\n\n        Electron.Tray.Show(\"/Assets/electron_32x32.png\", menu);\n        Electron.Tray.SetToolTip(\"Electron Demo in the tray.\");\n    }\n    else\n    {\n        Electron.Tray.Destroy();\n    }\n\n});</code></pre>\n                    <h5>Renderer Process (JavaScript)</h5>\n                    <pre><code class=\"javascript\">const { ipcRenderer } = require(\"electron\");\n\nlet trayOn = false;\ndocument.getElementById(\"put-in-tray\").addEventListener(\"click\", () => {\n    ipcRenderer.send(\"put-in-tray\");\n    \n    let message = '';\n    \n    if(trayOn) {\n        trayOn = false;\n    } else {\n        trayOn = true;\n        message = 'Click demo again to remove.'\n    }\n\n    document.getElementById('tray-countdown').innerHTML = message;</code></pre>\n\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Tray support in Linux.</strong>\n                        <p>On Linux distributions that only have app indicator support, users will need to install <code>libappindicator1</code> to make the tray icon work. See the <a href=\"http://electron.atom.io/docs/api/tray\">full API documentation<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a> for more details about using Tray on Linux.</p>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <script>\n            (function(){\n                const { ipcRenderer } = require(\"electron\");\n\n                let trayOn = false;\n                document.getElementById(\"put-in-tray\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"put-in-tray\");\n                    \n                    let message = '';\n                    \n                    if(trayOn) {\n                        trayOn = false;\n                    } else {\n                        trayOn = true;\n                        message = 'Click demo again to remove.'\n                    }\n\n                    document.getElementById('tray-countdown').innerHTML = message;\n                });\n            }());\n        </script>\n\n    </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Update/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"update-section\" class=\"section js-section u-category-update\">\n        <header class=\"section-header\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-update\"></use></svg>\n                    Update\n                </h1>\n                <h3>The <code>Electron.AutoUpdater</code> allows you to automatically update your application.</h3>\n                <p>To publish your updates you just need simple file hosting, it does not require a dedicated server.</p>\n                <p>You find the sample source code in <code>Controllers\\UpdateController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"tray-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Auto Update this App\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux | Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"btn-update\">View Demo</button>\n                        <span class=\"demo-response\" id=\"demo-reply\"></span>\n                    </div>\n                    <p>The demo button call the <code>Electron.AutoUpdater.CheckForUpdatesAndNotifyAsync()</code> in the main process.</p>\n\n                    <p>This will immediately download an update, then install in the background when the app quits.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">Electron.IpcMain.On(\"auto-update\", async (args) =>\n{\n    var currentVersion = await Electron.App.GetVersionAsync();\n    var updateCheckResult = await Electron.AutoUpdater.CheckForUpdatesAndNotifyAsync();\n    var availableVersion = updateCheckResult.UpdateInfo.Version;\n    string information = $\"Current version: {currentVersion} - available version: {availableVersion}\";\n\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    Electron.IpcMain.Send(mainWindow, \"auto-update-reply\", information);\n});\n</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <script>\n            (function(){\n                const { ipcRenderer } = require(\"electron\");\n\n                document.getElementById(\"btn-update\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"auto-update\");\n                });\n\n                ipcRenderer.on('auto-update-reply', (event, message) => {\n                    document.getElementById('demo-reply').innerHTML = message;\n                });\n            }());\n        </script>\n\n    </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Windows/DemoWindow.cshtml",
    "content": "﻿<style>\n    body {\n        font-family: system, -apple-system, '.SFNSText-Regular', 'SF UI Text', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif;\n        color: #fff;\n        background-color: #8aba87;\n        text-align: center;\n        font-size: 40px;\n    }\n\n    h2 {\n        padding: 0;\n        margin: 0;\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        transform: translate(-50%, -50%);\n    }\n\n    #close {\n        color: white;\n        opacity: 0.7;\n        position: absolute;\n        bottom: 20px;\n        left: 50%;\n        transform: translateX(-50%);\n        font-size: 12px;\n        text-decoration: none;\n    }\n</style>\n\n<h2>Hello World!</h2>\n<a id=\"close\" href=\"javascript:window.close()\">Close this Window</a>"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Windows/HandleErrorCrashes.cshtml",
    "content": "﻿"
  },
  {
    "path": "src/ElectronNET.WebApp/Views/Windows/Index.cshtml",
    "content": "﻿<template class=\"task-template\">\n    <section id=\"windows-section\" class=\"section js-section u-category-windows\">\n        <header class=\"section-header\">\n            <div class=\"section-wrapper\">\n                <h1>\n                    <svg class=\"section-icon\"><use xlink:href=\"assets/img/icons.svg#icon-windows\"></use></svg>\n                    Create and Manage Windows\n                </h1>\n                <h3>The <code>Electron.WindowManager</code> in Electron.NET allows you to create a new browser window or manage an existing one.</h3>\n\n                <p>Each browser window is a separate process, known as the renderer process. This process, like the main process that controls the life cycle of the app, has full access to the .NET Core and Node.js APIs.\n\n                <p>You find the sample source code in <code>Controllers\\WindowsController.cs</code>.</p>\n            </div>\n        </header>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"new-window-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Create a new window\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"new-window\">View Demo</button>\n                    </div>\n                    <p>The <code>Electron.WindowManager</code> gives you the ability to create new windows in your app. This main process can be used from the renderer process with the <code>Electron.IpcMain</code>, as is shown in this demo.</p>\n\n                    <p>There are a lot of options when creating a new window. A few are in this demo, but visit the <a href=\"http://electron.atom.io/docs/api/browser-window\">documentation<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a> for the full list.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">await Electron.WindowManager.CreateWindowAsync();</code></pre>\n\n                    <div class=\"demo-protip\">\n                        <h2>ProTip</h2>\n                        <strong>Use an invisible browser window to run background tasks.</strong>\n                        <p>You can set a new browser window to not be shown (be invisible) in order to use that additional renderer process as a kind of new thread in which to run C# in the background of your app. You do this by setting the <code>show</code> property to <code>false</code> when defining the new window.</p>\n                        <pre>\n<code class=\"csharp\">\npublic async void ElectronBootstrap()\n{\n    var browserWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions\n    {\n        Show = false\n    });\n\n    browserWindow.OnReadyToShow += () => browserWindow.Show();\n}\n</code></pre>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"manage-window-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Manage window state\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"manage-window\">View Demo</button>\n                        <span class=\"demo-response\" id=\"manage-window-reply\"></span>\n                    </div>\n                    <p>In this demo we create a new window and listen for <code>OnMove</code> and <code>OnResize</code> events on it. Click the demo button, change the new window and see the dimensions and position update here, above.</p>\n                    <p>There are a lot of methods for controlling the state of the window such as the size, location, and focus status as well as events to listen to for window changes. Visit the <a href=\"http://electron.atom.io/docs/api/browser-window\">documentation<span class=\"u-visible-to-screen-reader\">(opens in new window)</span></a> for the full list.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">public IActionResult Index()\n{\n    Electron.IpcMain.On(\"manage-window\", async (args) => {\n\n        var browserWindow = await Electron.WindowManager.CreateWindowAsync();\n        browserWindow.OnMove += UpdateReply;\n        browserWindow.OnResize += UpdateReply;\n    });\n\n    return View();\n}\n\nprivate async void UpdateReply()\n{\n    var browserWindow = Electron.WindowManager.BrowserWindows.Last();\n    var size = await browserWindow.GetSizeAsync();\n    var position = await browserWindow.GetPositionAsync();\n    string message = $\"Size: {size[0]},{size[1]} Position: {position[0]},{position[1]}\";\n\n    var mainWindow = Electron.WindowManager.BrowserWindows.First();\n    Electron.IpcMain.Send(mainWindow, \"manage-window-reply\", message);\n}</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button id=\"using-window-events-demo-toggle\" class=\"js-container-target demo-toggle-button\">\n                    Window events: blur and focus\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"listen-to-window\">View Demo</button>\n                        <button class=\"demo-button disappear\" id=\"focus-on-modal-window\">Focus on Demo</button>\n                    </div>\n                    <p>In this demo, we create a new window and listen for <code>OnBlur</code> event on it. Click the demo button to create a new modal window, and switch focus back to the parent window by clicking on it. You can click the <i>Focus on Demo</i> button to switch focus to the modal window again.</p>\n                    <h5>Main Process (C#)</h5>\n                    <pre><code class=\"csharp\">var mainBrowserWindow = Electron.WindowManager.BrowserWindows.First();\n\nvar browserWindow = await Electron.WindowManager.CreateWindowAsync();\nbrowserWindow.OnFocus += () => Electron.IpcMain.Send(mainBrowserWindow, \"listen-to-window-focus\");\nbrowserWindow.OnBlur += () => Electron.IpcMain.Send(mainBrowserWindow, \"listen-to-window-blur\");\n\nElectron.IpcMain.On(\"listen-to-window-set-focus\", (x) => browserWindow.Focus());</code></pre>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"demo\">\n            <div class=\"demo-wrapper\">\n                <button class=\"js-container-target demo-toggle-button\">\n                    Create a frameless window\n                    <div class=\"demo-meta u-avoid-clicks\">Supports: Win, macOS, Linux <span class=\"demo-meta-divider\">|</span> Process: Main</div>\n                </button>\n                <div class=\"demo-box\">\n                    <div class=\"demo-controls\">\n                        <button class=\"demo-button\" id=\"frameless-window\">View Demo</button>\n                    </div>\n                    <p>\n                        A frameless window is a window that has no <a href=\"https://developer.mozilla.org/en-US/docs/Glossary/Chrome\">\"chrome\"</a>,\n                        such as toolbars, title bars, status bars, borders, etc. You can make a browser window frameless by setting\n                        <code>Frame</code> to <code>false</code> when creating the window.\n                    </p>\n\n                    <h5>Main Process</h5>\n                    <pre><code class=\"csharp\">var options = new BrowserWindowOptions\n{\n    Frame = false\n};\nawait Electron.WindowManager.CreateWindowAsync(options);</code></pre>\n\n                    <p>Windows can have a transparent background, too. By setting the <code>Transparent</code> option to <code>true</code>, you can also make your frameless window transparent:</p>\n                    <pre>\n<code class=\"csharp\">var options = new BrowserWindowOptions\n{\n    Frame = false,\n    Transparent = true\n};\nawait Electron.WindowManager.CreateWindowAsync(options);</code></pre>\n\n                    <p>\n                        For more details, see the <a href=\"http://electron.atom.io/docs/api/frameless-window/\">Frameless Window</a> documentation.\n                    </p>\n\n                </div>\n            </div>\n        </div>\n\n        <script>\n            (function(){\n                const { ipcRenderer } = require(\"electron\");\n                \n                document.getElementById(\"new-window\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"new-window\");\n                });\n\n                document.getElementById(\"manage-window\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"manage-window\");\n                });\n\n                ipcRenderer.on(\"manage-window-reply\", (sender, data) => {\n                    document.getElementById(\"manage-window-reply\").innerText = data;\n                });\n                \n                document.getElementById(\"listen-to-window\").addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"listen-to-window\");\n                });\n\n                document.getElementById('focus-on-modal-window').addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"listen-to-window-set-focus\");\n                });\n\n                ipcRenderer.on(\"listen-to-window-focus\", (sender, data) => {\n                    const focusModalBtn = document.getElementById('focus-on-modal-window');\n                    focusModalBtn.classList.add('disappear');\n                    focusModalBtn.classList.remove('smooth-appear');\n                });\n\n                ipcRenderer.on(\"listen-to-window-blur\", (sender, data) => {\n                    const focusModalBtn = document.getElementById('focus-on-modal-window');\n                    focusModalBtn.classList.add('smooth-appear');\n                    focusModalBtn.classList.remove('disappear');\n                });\n\n                document.getElementById('frameless-window').addEventListener(\"click\", () => {\n                    ipcRenderer.send(\"frameless-window\");\n                });\n            }());\n        </script>\n\n    </section>\n</template>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/appsettings.Development.json",
    "content": "﻿{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Debug\",\n      \"System\": \"Information\",\n      \"Microsoft\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/appsettings.json",
    "content": "﻿{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Warning\"\n    }\n  },\n  \"DemoTitleInSettings\": \"Electron.NET API Demos\"\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/code-blocks.js",
    "content": "document.addEventListener('DOMContentLoaded', function () {\n  setTimeout(() => {\n    const codeBlocks = document.querySelectorAll('pre code');\n    Array.prototype.forEach.call(codeBlocks, function (code) {\n      hljs.highlightBlock(code)\n    });\n  }, 1000);\n})\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/css/about.css",
    "content": "/* Welcome ------------------------ */\n\n.about {\n  --about-space: 2rem;\n\n  position: absolute;\n  display: flex;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  z-index: 1;\n  overflow-x: hidden;\n  overflow-y: auto;\n  padding: 0;\n  background-color: hsl(0,0%,98%);\n  pointer-events: none;\n  visibility: hidden;\n  opacity: 0;\n  transform: scale(1.1);\n  transition: visibility 0s .12s linear , opacity .12s ease-in, transform .12s ease-in;\n}\n.about.is-shown {\n  pointer-events: auto;\n  visibility: visible;\n  opacity: 1;\n  transform: scale(1);\n  transition: visibility 0s 0s linear , opacity .24s ease-out, transform .24s ease-out;\n}\n\n.about-wrapper {\n  margin: auto;\n}\n\n.about-header {\n  padding: var(--about-space) 0;\n  border-bottom: 1px solid hsl(0,0%,88%);\n}\n\n.about-logo {\n  display: block;\n  margin: 0 auto;\n  width: 320px; /* TODO: Adjust asset to this size */\n  max-width: 100%;\n}\n\n.about-sections {\n  max-width: 680px;\n  padding: 0 var(--about-space);\n}\n\n.about-section {\n  margin: var(--about-space) 0;\n}\n\n.about h2 {\n  text-align: center;\n  margin: 0 0 1em 0;\n  font-size: 1.5em;\n  color: hsl(0, 0%, 55%);\n}\n\n.about .about-code h2 {\n  color: hsl(330, 65%, 55%);\n}\n\n.about .play-along h2 {\n  color: hsl(222, 53%, 50%);\n}\n\n.about-button {\n  display: block;\n  margin: 0 auto;\n  padding: .4em 1.2em;\n  font: inherit;\n  font-size: 1.6em;\n  color: inherit;\n  border: 2px solid;\n  border-radius: 4px;\n  background-color: transparent;\n}\n.about-button:focus {\n  outline: none;\n  border-color: hsl(0,0%,88%);\n}\n\nfooter.about-section {\n  text-align: center;\n}\n\n.rainbow-button-wrapper {\n  --rainbow-button-width: 170px;\n  --rainbow-button-height: 50px;\n  --rainbow-button-width-inner: 164px;\n  --rainbow-button-height-inner: 44px;\n  --rainbow-color-1: hsl(116, 30%, 36%);\n  --rainbow-color-2: hsl(194, 60%, 36%);\n  --rainbow-color-3: hsl(222, 53%, 50%);\n  --rainbow-color-4: hsl(285, 47%, 46%);\n  --rainbow-color-5: hsl(330, 65%, 48%);\n  --rainbow-color-6: hsl(32, 79%, 49%);\n  --rainbow-color-7: hsl(53, 84%, 50%);\n\n  display: inline-block;\n  width: var(--rainbow-button-width);\n  height: var(--rainbow-button-height);\n  position: relative;\n  overflow: hidden;\n  border-radius: 5px;\n}\n\n.rainbow-button-wrapper:before {\n  display: block;\n  position: absolute;\n  z-index: 2;\n  top: 0;\n  left: 0;\n  width: 600px;\n  height: var(--rainbow-button-height);\n  background: #CCC;\n  background: linear-gradient(to right, var(--rainbow-color-1) 0%, var(--rainbow-color-2) 14%, var(--rainbow-color-3) 28%, var(--rainbow-color-4) 42%, var(--rainbow-color-5) 56%, var(--rainbow-color-6) 70%, var(--rainbow-color-7) 84%, var(--rainbow-color-1) 100%);\n  background-position: -200px 0;\n  transition: all 0.5s;\n  content: \"\";\n}\n\n.rainbow-button-wrapper button {\n  display: block;\n  width: var(--rainbow-button-width-inner);\n  height: var(--rainbow-button-height-inner);\n  position: absolute;\n  z-index: 3;\n  top: 3px;\n  left: 3px;\n  border: none;\n  background: white;\n  color: black;\n  font-size: 1.3rem;\n}\n\n.rainbow-button-wrapper:hover:before {\n  background-position: 200px 0;\n}\n\n@media (min-width: 940px) {\n  .about-header {\n    align-self: center;\n    padding: var(--about-space);\n    border-right: 1px solid hsl(0,0%,88%);\n    border-bottom: none;\n  }\n  .about-wrapper {\n    display: flex;\n  }\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/css/demo.css",
    "content": "/* Demo */\n\n.demo:first-of-type {\n  margin-top: 2rem;\n}\n.demo:last-of-type {\n  margin-bottom: 2rem;\n}\n@media (min-width: 940px) {\n  .demo:last-of-type {\n    margin-bottom: 4rem;\n  }\n}\n\n.demo-wrapper {\n  position: relative;\n  max-width: 740px;\n  margin: 0 auto;\n  padding: 0 2rem;\n}\n\n\n/* Toggle Button ----------------------------- */\n\n.demo-toggle-button {\n  position: relative;\n  display: block;\n  margin: 0;\n  padding: .5em 1.5em;\n  line-height: 1.5;\n  font: inherit;\n  font-weight: 600;\n  font-size: 1.2em;\n  text-align: left;\n  border: none;\n  color: inherit;\n  background-color: transparent;\n  transition: border-color .12s;\n  outline: none;\n}\n\n.demo-toggle-button:before,\n.demo-toggle-button:after {\n  content: \"\";\n  position: absolute;\n  left: 0;\n  width: 2px;\n  height: 50%;\n  background-color: hsl(0,0%,88%);\n  transition: transform .2s cubic-bezier(.4,.1,0,1);\n}\n.demo-toggle-button:before {\n  top: 0;\n  transform-origin: bottom center;\n  transform: translateX(.7em) rotate(-30deg) scale(.75);\n}\n.demo-toggle-button:after {\n  bottom: 0;\n  transform-origin: top center;\n  transform: translateX(.7em) rotate(30deg) scale(.75);\n}\n.is-open .demo-toggle-button:before,\n.is-open .demo-toggle-button:after {\n  transform: rotate(0deg);\n}\n.demo-toggle-button:focus:before,\n.demo-toggle-button:focus:after {\n  background-color: currentColor;\n}\n\n/* Meta info */\n\n.demo-meta {\n  margin-top: .2em;\n  font-size: 11px;\n  font-weight: 300;\n  text-transform: uppercase;\n  color: var(--color-subtle);\n}\n.demo-meta-divider {\n  margin: 0 .5em;\n}\n\n\n/* Demo Box ----------------------------- */\n\n.demo-box {\n  display: none;\n  position: relative;\n  padding: 2em;\n  margin-top: 1em;\n  margin-bottom: 2em;\n  border-radius: 6px;\n  border: 1px solid var(--color-border);\n  background-color: var(--color-bg);\n}\n.demo-box:before {\n  content: \"\";\n  position: absolute;\n  top: -11px;\n  width: 20px;\n  height: 20px;\n  background-color: inherit;\n  border-top: inherit;\n  border-right: inherit;\n  border-top-right-radius: 3px;\n  transform: rotate(-45deg);\n}\n\n.is-open .demo-box {\n  display: block;\n  animation: demo-box-fade-in .2s cubic-bezier(0, .20, .20, .96);\n}\n@keyframes demo-box-fade-in {\n    0% { opacity: 0; transform: translateY(-20px); }\n  100% { opacity: 1; transform: translateY(0); }\n}\n\n.demo-box > p:first-child {\n  margin-top: 0;\n}\n\n.demo-box h5 {\n  font-size: 1em;\n  margin-bottom: .6em;\n}\n\n\n/* Demo Controls ----------------------------- */\n\n.demo-controls {\n  display: flex;\n  align-items: center;\n}\n\n.demo-button {\n  align-self: flex-start;\n  margin-right: 1em;\n  border: 2px solid;\n  border-radius: 4px;\n  font: inherit;\n  font-size: 1.2em;\n  padding: .4em 1.2em;\n  color: inherit;\n  background-color: transparent;\n}\n.demo-button:focus {\n  outline: none;\n  background-color: white;\n}\n.demo-button:active {\n  border-color: var(--color-border);\n}\n\n.demo-input {\n  flex: 1;\n  border: 2px solid var(--color-border);\n  border-radius: 4px;\n  font: inherit;\n  font-size: 1.2em;\n  padding: .4em .8em;\n  color: inherit;\n  background-color: transparent;\n}\n.demo-input:focus {\n  outline: none;\n  border-color: hsl(0,0%,80%);\n  background-color: white;\n}\n\n.demo-response {\n  flex: 1;\n  word-break: break-word;\n}\n\n.smooth-appear {\n  opacity: 1;\n  transition: opacity .5s ease-in-out;\n}\n\n.disappear {\n  opacity: 0;\n}\n.demo-button.smooth-disappear:focus {\n  outline: inherit;\n  border-color: inherit;\n  background-color: inherit;\n}\n\n/* ProTip ----------------------------- */\n\n.demo-protip {\n  margin-top: 2rem;\n  padding: 1.5rem 2rem 2rem 2rem;\n  border: 1px solid hsla(0,0%,0%,.06);\n  border-radius: 6px;\n  background: var(--color-accent) linear-gradient(hsla(0,0%,100%,.85), hsla(0,0%,100%,.85));\n}\n.demo-protip h2 {\n  margin: 0 0 .5rem 0;\n}\n.demo-protip strong {\n  font-weight: 600;\n}\n\n/* Clipboard paste image ------------------ */\n.demo-image-box {\n    padding-left: 15px;\n}"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/css/github.css",
    "content": "/*\n\ngithub.com style (c) Vasily Polovnyov <vast@whiteants.net>\n\n*/\n\n.hljs {\n  display: block;\n  overflow-x: auto;\n  padding: 0.5em;\n  color: #333;\n  background: #f8f8f8;\n}\n\n.hljs-comment,\n.hljs-quote {\n  color: #998;\n  font-style: italic;\n}\n\n.hljs-keyword,\n.hljs-selector-tag,\n.hljs-subst {\n  color: #333;\n  font-weight: bold;\n}\n\n.hljs-number,\n.hljs-literal,\n.hljs-variable,\n.hljs-template-variable,\n.hljs-tag .hljs-attr {\n  color: #008080;\n}\n\n.hljs-string,\n.hljs-doctag {\n  color: #d14;\n}\n\n.hljs-title,\n.hljs-section,\n.hljs-selector-id {\n  color: #900;\n  font-weight: bold;\n}\n\n.hljs-subst {\n  font-weight: normal;\n}\n\n.hljs-type,\n.hljs-class .hljs-title {\n  color: #458;\n  font-weight: bold;\n}\n\n.hljs-tag,\n.hljs-name,\n.hljs-attribute {\n  color: #000080;\n  font-weight: normal;\n}\n\n.hljs-regexp,\n.hljs-link {\n  color: #009926;\n}\n\n.hljs-symbol,\n.hljs-bullet {\n  color: #990073;\n}\n\n.hljs-built_in,\n.hljs-builtin-name {\n  color: #0086b3;\n}\n\n.hljs-meta {\n  color: #999;\n  font-weight: bold;\n}\n\n.hljs-deletion {\n  background: #fdd;\n}\n\n.hljs-addition {\n  background: #dfd;\n}\n\n.hljs-emphasis {\n  font-style: italic;\n}\n\n.hljs-strong {\n  font-weight: bold;\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/css/global.css",
    "content": "/* Fonts ---------------------------- */\n\n@font-face {\n  font-family: 'Source Code Pro';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Source Code Pro'), local('SourceCodePro'), url(fonts/SourceCodePro-Regular.ttf) format('truetype');\n}\n\n\n/* Global ---------------------------- */\n\n* {\n  box-sizing: border-box;\n}\n\nhtml {\n  height: 100%;\n  font-family: 'BlinkMacSystemFont', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif;\n  font-size: 14px;\n  line-height: 1.5;\n  overflow: hidden; /* Prevents rubber-band scrolling of the whole \"page\" */\n  color: var(--color);\n  background-color: #fff; /* To cover OSes with no default background color */\n}\n\nbody {\n  margin: 0;\n  height: 100%;\n  display: flex;\n}\n\na {\n  color: var(--color-link);\n}\n\nh1,\nh2,\nh3 {\n  margin-top: 0;\n  line-height: 1.5;\n}\n\nh1 {\n  font-size: 1.5em;\n  font-weight: 600;\n}\n\nh2 {\n  font-size: 1.3em;\n  font-weight: normal;\n}\n\nh3 {\n  font-size: 1.12em;\n  font-weight: 600;\n}\n\ntable {\n  width: 100%;\n  border-spacing: 0;\n  border: 1px solid hsla(0,0%,0%,.08);\n  border-width: 0 1px 1px 0;\n}\nth {\n  background-color: hsla(0,0%,50%,.06);\n}\nth,\ntd {\n  text-align: center;\n  border: 1px solid hsla(0,0%,0%,.08);\n  border-width: 1px 0 0 1px;\n}\n\nsvg {\n  fill: currentColor;\n}\n\n/* Code */\n\ncode, kbd {\n  font-family: 'Source Code Pro', monospace;\n  border-radius: 4px;\n  padding: 1px 4px;\n  white-space: nowrap;\n  color: hsl(0,0%,36%);\n  background-color: hsla(0,0%,60%,.15);\n}\n\npre, kbd {\n  font-size: 13px;\n  overflow: auto;\n  padding: 1em;\n  margin: 0;\n  border-radius: 4px;\n  border: 1px solid;\n  border-color: var(--color-border);\n  background-color: white;\n}\n\npre code {\n  white-space: pre;\n}\n\npre > .hljs {\n  color: var(--color-subtle);\n  background-color: white;\n}\n\nkbd {\n  padding: 0.5em;\n}\n\n\n/* Utilities ---------------------------- */\n\n.u-avoid-clicks {\n  pointer-events: none;\n}\n\n/* Visually hidden, but will be read by screen readers */\n.u-visible-to-screen-reader {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n\n.no-display {\n  display: none;\n}\n\n\n/* Content ------------------ */\n\n.content {\n  flex: 1;\n  position: relative;\n  overflow: hidden;\n  visibility: hidden;\n  opacity: 0;\n}\n.content.is-shown {\n  visibility: visible;;\n  opacity: 1;\n}\n\n\n/* Hacks ---------------------------- */\n\n/* Fixes horizontal scrolling in code blocks on OS X El Cap (10.11.3), retina screen\n *\n * By adding an invisible outline property, it will force a repaint\n * which enables the scrolling.\n */\n\n.hljs:hover,\n.hljs:active {\n  outline: 1px solid transparent;\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/css/nativize.css",
    "content": "/*\n** nativize.css\n** Makes the UI feel more native\n*/\n\nhtml {\n  font-family: sans-serif;\n  -webkit-user-select: none; /* disable selection */\n  -webkit-user-drag: none; /* disable dragging */\n  cursor: default; /* use default cursor */\n}\n\nbody {\n  margin: 0; /* remove default margin */\n}\n\n\n/* enable text selection */\n\n/*.is-selectable,*/\n\npre,\ncode {\n  -webkit-user-select: auto;\n  user-select: text;\n  cursor: auto;\n}\n\n\n/* Buttons and links */\n\nbutton{\n  cursor: default;\n}\n\n/* Internal links */\na {\n  cursor: pointer;\n  text-decoration: none;\n  border-bottom: 1px dashed;\n  outline: none;\n}\n\n/* New window (target) + external links */\na[target],\na[href^=\"https://\"],\na[href^=\"http://\"] {\n  border-bottom: 1px solid;\n}\n\na:hover,\na:focus {\n  border-bottom: none;\n}\n\n\n/* Images */\n\nimg {\n  -webkit-user-drag: none; /* disable dragging */\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/css/nav.css",
    "content": "/* Nav */\n\n.nav {\n  width: 340px;\n  overflow-x: hidden;\n  overflow-y: auto;\n  color: var(--color-subtle);\n  border-right: 1px solid var(--color-border);\n  background-color: var(--color-bg);\n  visibility: hidden;\n  opacity: 0;\n}\n.nav.is-shown {\n  visibility: visible;;\n  opacity: 1;\n}\n\n.nav-header {\n  position: relative;\n  padding: 2rem;\n  margin-bottom: 1rem;\n  border-bottom: 1px solid var(--color-border);\n}\n\n.nav-title {\n  text-transform: uppercase;\n  font-weight: 300;\n  line-height: 1;\n  margin: 0;\n}\n\n.nav-title strong {\n  font-weight: 600;\n  color: var(--color-strong);\n}\n\n.nav-header-icon {\n  position: absolute;\n  width: 36px;\n  height: 36px;\n  top: 1.5rem; /* magic */\n  right: 1.75rem; /* magic */\n}\n\n\n\n.nav-item {\n  padding: .5em 0;\n}\n\n.nav-icon {\n  width: 16px;\n  height: 16px;\n  vertical-align: top;\n  margin-right: .25rem;\n}\n\n.nav-category {\n  margin: .2em 0;\n  padding-left: 2rem;\n  font-size: 11px;\n  font-weight: normal;\n  text-transform: uppercase;\n}\n\n.nav-button {\n  display: block;\n  width: 100%;\n  padding: .3rem;\n  padding-left: calc(2rem + 16px + .5rem); /* padding + icon + magic */\n  line-height: 2;\n  text-align: left;\n  font: inherit;\n  font-size: 13px;\n  color: inherit;\n  border: none;\n  background-color: transparent;\n  cursor: default;\n  outline: none;\n}\n.nav-button:hover,\n.nav-button:focus:not(.is-selected) {\n  background-color: hsla(0,0%,0%,.1);\n}\n.nav-button.is-selected {\n  background-color: var(--color-accent);\n}\n.nav-button.is-selected,\n.nav-button.is-selected em {\n  color: #fff;\n}\n.nav-button.is-selected:focus {\n  opacity: .8;\n}\n\n.nav-button em {\n  font-style: normal;\n  font-weight: 600;\n  color: var(--color-strong);\n  pointer-events: none; /* makes it invisible to clicks */\n}\n\n.nav-footer {\n  margin-top: 1rem;\n  padding: 2rem;\n  border-top: 1px solid var(--color-border);\n  text-align: center;\n}\n\n.nav-footer-icon {\n  width: calc(770px / 6.5);\n  height: calc(88px / 6.5);\n}\n\n.nav-footer a {\n  outline: none;\n}\n\n.nav-footer-button {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: .75rem;\n  line-height: 2;\n  text-align: left;\n  font: inherit;\n  font-size: 13px;\n  color: inherit;\n  border: none;\n  background-color: transparent;\n  cursor: default;\n  outline: none;\n  text-align: center;\n}\n.nav-footer-button:focus {\n  color: var(--color-strong);\n}\n\n.nav-footer-logo {\n  color: hsl(0,0%,66%);\n}\n.nav-footer-logo:focus {\n  color: hsl(0,0%,33%);\n}\n\n/* Remove border on the logo */\n.nav-footer-logo.nav-footer-logo {\n  border-bottom: none;\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/css/print.css",
    "content": "@media print {\n  body {\n    background: none;\n    color: black !important;\n    font-size: 70%;\n    margin: 0; padding: 0;\n  }\n\n  h1 {\n    font-size: 22px;\n  }\n\n  .nav, button, .demo-box:before,\n  #pdf-path, header p {\n    display: none;\n  }\n\n  .demo-box, h2,\n  pre, code {\n    padding: 0 !important;\n    margin: 0 !important;\n  }\n\n  header {\n    padding: 0 0 10px 0;\n  }\n\n  code, .support {\n    font-size: 10px;\n  }\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/css/section.css",
    "content": "/* Section ------------------ */\n\n.section {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  overflow-x: hidden;\n  overflow-y: auto;\n  color: var(--color-accent);\n\n  /* Hide */\n  pointer-events: none;\n  visibility: hidden;\n  opacity: 0;\n  transform: translateX(-20px);\n  transition: visibility 0s .12s linear , opacity .12s ease-in, transform .12s ease-in;\n}\n.section.is-shown {\n  pointer-events: auto;\n  visibility: visible;\n  opacity: 1;\n  transform: translateX(0);\n  transition: visibility 0s 0s linear , opacity .36s ease-out, transform .36s ease-out;\n}\n\n.section h3,\n.section p {\n  color: var(--color);\n}\n\n.section-wrapper {\n  position: relative;\n  max-width: 740px;\n  margin: 0 auto;\n  padding: 2rem 2rem 1rem 2rem;\n  border-bottom: 1px solid var(--color-border);\n}\n@media (min-width: 940px) {\n  .section-wrapper {\n    padding-top: 4rem;\n  }\n}\n\n.section-icon {\n  width: 32px;\n  height: 32px;\n  vertical-align: middle;\n  margin-right: .5em;\n}\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/css/variables.css",
    "content": "\n/* Custom Properties */\n\n:root {\n  --color:          hsl(0,0%,22%);\n  --color-subtle:   hsl(0,0%,44%);\n  --color-strong:   hsl(0,0%,11%);\n  --color-link:     hsl(0,0%,22%);\n\n  --color-border:   hsl(0,0%,88%);\n  --color-bg:       hsl(0,0%,96%);\n\n  --color-accent:   black; /* Fallback */\n}\n\n\n/* Category Colors */\n\n.u-category-windows       { --color-accent: hsl(116, 30%, 36%); }\n.u-category-menu          { --color-accent: hsl(194, 60%, 36%); }\n.u-category-native-ui     { --color-accent: hsl(222, 53%, 50%); }\n.u-category-communication { --color-accent: hsl(285, 47%, 46%); }\n.u-category-system        { --color-accent: hsl(330, 65%, 48%); }\n.u-category-update        { --color-accent: hsl(0, 92%, 43%); }\n.u-category-media      { --color-accent: hsl( 36, 77%, 34%); }\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/demo-btns.js",
    "content": "setTimeout(() => {\n  const demoBtns = document.querySelectorAll('.js-container-target');\n  \n  // Listen for demo button clicks\n  Array.prototype.forEach.call(demoBtns, function (btn) {\n    btn.addEventListener('click', function (event) {\n        const parent = event.target.parentElement;\n  \n      // Toggles the \"is-open\" class on the demo's parent element.\n      parent.classList.toggle('is-open');\n    })\n  })\n}, 3000);\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/ex-links.js",
    "content": "(function () {\n    const shell = require('electron').shell\n    const links = document.querySelectorAll('a[href]')\n\n    Array.prototype.forEach.call(links, function (link) {\n        const url = link.getAttribute('href')\n        if (url.indexOf('http') === 0) {\n            link.addEventListener('click', function (e) {\n                e.preventDefault()\n                shell.openExternal(url)\n            })\n        }\n    })\n})\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/imports.js",
    "content": "const links = [\"windows\", \"crashhang\", \"menus\", \"shortcuts\", \"shell\", \"notifications\", \"dialogs\", \"tray\", \"ipc\", \"hosthook\", \"appsysinformation\", \"clipboard\", \"pdf\", \"desktopcapturer\", \"update\"];\n\nfetch('about').then((aboutPage) => {\n  aboutPage.text().then(pageContent => {\n    const template = document.createRange().createContextualFragment(pageContent);\n    document.querySelector('body').appendChild(template.firstElementChild.content);\n  });\n});\n\nlinks.forEach(async pageName => {\n  const page = await fetch(pageName);\n  const pageContent = await page.text();\n  const template = document.createRange().createContextualFragment(pageContent);\n  document.querySelector('.content').appendChild(template.firstElementChild.content);\n});"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/mac/child.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n  <dict>\n    <key>com.apple.security.app-sandbox</key>\n    <true/>\n    <key>com.apple.security.inherit</key>\n    <true/>\n  </dict>\n</plist>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/mac/info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n  <key>CFBundleURLTypes</key>\n  <array>\n    <dict>\n      <key>CFBundleURLSchemes</key>\n      <array>\n        <string>electron-api-demos</string>\n      </array>\n      <key>CFBundleURLName</key>\n      <string>Electron API Demos Protocol</string>\n    </dict>\n  </array>\n  <key>ElectronTeamID</key>\n  <string>VEKTX9H2N7</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/mac/parent.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n  <dict>\n    <key>com.apple.security.app-sandbox</key>\n    <true/>\n    <key>com.apple.security.application-groups</key>\n    <string>VEKTX9H2N7.com.github.electron-api-demos</string>\n    <key>com.apple.security.files.user-selected.read-write</key>\n    <true/>\n  </dict>\n</plist>\n"
  },
  {
    "path": "src/ElectronNET.WebApp/wwwroot/assets/nav.js",
    "content": "document.body.addEventListener('click', function (event) {\n    if (event.target.dataset.section) {\n        handleSectionTrigger(event)\n    } else if (event.target.dataset.modal) {\n        handleModalTrigger(event)\n    } else if (event.target.classList.contains('modal-hide')) {\n        hideAllModals()\n    }\n});\n\nfunction handleSectionTrigger(event) {\n    hideAllSectionsAndDeselectButtons();\n\n    // Highlight clicked button and show view\n    event.target.classList.add('is-selected');\n\n    // Display the current section\n    const sectionId = event.target.dataset.section + '-section'\n    document.getElementById(sectionId).classList.add('is-shown');\n}\n\nfunction activateDefaultSection() {\n    document.getElementById('button-windows').click()\n}\n\nfunction showMainContent() {\n    showNav();\n    document.querySelector('.js-content').classList.add('is-shown');\n}\n\nfunction handleModalTrigger(event) {\n    hideAllModals();\n    const modalId = event.target.dataset.modal + '-modal';\n\n    if (modalId === 'about-modal') {\n        hideNav();\n    }\n\n    document.getElementById(modalId).classList.add('is-shown');\n}\n\nfunction hideAllModals() {\n    const modals = document.querySelectorAll('.modal.is-shown')\n    Array.prototype.forEach.call(modals, function (modal) {\n        modal.classList.remove('is-shown')\n    })\n    showMainContent()\n}\n\nfunction hideAllSectionsAndDeselectButtons() {\n    const sections = document.querySelectorAll('.js-section.is-shown')\n    Array.prototype.forEach.call(sections, function (section) {\n        section.classList.remove('is-shown')\n    })\n\n    const buttons = document.querySelectorAll('.nav-button.is-selected')\n    Array.prototype.forEach.call(buttons, function (button) {\n        button.classList.remove('is-selected')\n    })\n}\n\nfunction displayAbout() {\n    hideNav();\n    document.querySelector('#about-modal').classList.add('is-shown')\n}\n\nfunction hideNav() {\n    document.querySelector('.js-nav').classList.remove('is-shown');\n    document.querySelector('.js-nav').style.display = 'none';\n}\n\nfunction showNav() {\n    document.querySelector('.js-nav').style.display = null;\n    document.querySelector('.js-nav').classList.add('is-shown');\n}\n\nsetTimeout(() => {\n    activateDefaultSection();\n    displayAbout();\n}, 1000);"
  },
  {
    "path": "src/ElectronNET.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 18\nVisualStudioVersion = 18.0.11205.157\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ElectronNET.WebApp\", \"ElectronNET.WebApp\\ElectronNET.WebApp.csproj\", \"{7C048379-401C-4345-B5E7-BE232DEA8157}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6} = {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24} = {8860606D-6847-F22A-5AED-DF4E0984DD24}\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ElectronNET.API\", \"ElectronNET.API\\ElectronNET.API.csproj\", \"{A78157BA-B754-45F1-969F-D6A513CA0E72}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ElectronNET.Build\", \"ElectronNET.Build\\ElectronNET.Build.csproj\", \"{829FC339-4785-4229-ABA5-53ADB544DA00}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ElectronNET\", \"ElectronNET\\ElectronNET.csproj\", \"{8860606D-6847-F22A-5AED-DF4E0984DD24}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00} = {829FC339-4785-4229-ABA5-53ADB544DA00}\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"!Config\", \"!Config\", \"{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t..\\Changelog.md = ..\\Changelog.md\n\t\tcommon.props = common.props\n\t\t..\\global.json = ..\\global.json\n\t\t..\\NuGet.config = ..\\NuGet.config\n\t\t..\\publish.cmd = ..\\publish.cmd\n\t\t..\\README.md = ..\\README.md\n\tEndProjectSection\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ElectronNET.AspNet\", \"ElectronNET.AspNet\\ElectronNET.AspNet.csproj\", \"{DD10D21A-D131-1D9C-33F9-406046E0C5B0}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ElectronNET.ConsoleApp\", \"ElectronNET.ConsoleApp\\ElectronNET.ConsoleApp.csproj\", \"{EE38A326-5DE8-AF09-9EB9-DF0878938783}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6} = {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24} = {8860606D-6847-F22A-5AED-DF4E0984DD24}\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Core\", \"Core\", \"{1BB6F634-2831-4496-83A6-BC6761DCEC8D}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Test Apps\", \"Test Apps\", \"{EDCBFC49-2AEE-4BAF-9368-4409298C52FC}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Build\", \"Build\", \"{985D39A7-5216-4945-8167-2FD0CB387BD8}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t..\\.github\\workflows\\Build and Publish.yml = ..\\.github\\workflows\\Build and Publish.yml\n\t\t..\\.github\\workflows\\integration-tests.yml = ..\\.github\\workflows\\integration-tests.yml\n\t\t..\\.github\\workflows\\PR Validation.yml = ..\\.github\\workflows\\PR Validation.yml\n\t\t..\\.github\\workflows\\pr-comment.yml = ..\\.github\\workflows\\pr-comment.yml\n\t\t..\\.github\\workflows\\publish-wiki.yml = ..\\.github\\workflows\\publish-wiki.yml\n\t\t..\\.github\\workflows\\retry-test-jobs.yml = ..\\.github\\workflows\\retry-test-jobs.yml\n\t\t..\\.github\\workflows\\trailing-whitespace-check.yml = ..\\.github\\workflows\\trailing-whitespace-check.yml\n\tEndProjectSection\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"_build\", \"..\\nuke\\_build.csproj\", \"{015CB06B-6CAE-209F-E050-21C3ACA5FE9F}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"!Docs\", \"!Docs\", \"{D36CDFFD-3438-42E4-A7FF-88BA19AC4964}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t..\\.github\\workflows\\publish-wiki.yml = ..\\.github\\workflows\\publish-wiki.yml\n\tEndProjectSection\nEndProject\nProject(\"{D954291E-2A0B-460D-934E-DC6B0785DB48}\") = \"Docs\", \"..\\docs\\Docs.shproj\", \"{06CAADC7-DE5B-47B4-AB2A-E9501459A2D1}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Test Projects\", \"Test Projects\", \"{75129C45-FC6F-41B0-A485-07F4A7E031ED}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ElectronNET.IntegrationTests\", \"ElectronNET.IntegrationTests\\ElectronNET.IntegrationTests.csproj\", \"{AE877E48-6B44-63C2-8EA0-DB58D096B553}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6} = {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}\n\tEndProjectSection\nEndProject\nProject(\"{54A90642-561A-4BB1-A94E-469ADEE60C69}\") = \"ElectronNET.Host\", \"ElectronNET.Host\\ElectronNET.Host.esproj\", \"{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ElectronNET.Samples.ElectronHostHook\", \"ElectronNET.Samples.ElectronHostHook\\ElectronNET.Samples.ElectronHostHook.csproj\", \"{B8D65F3A-7E54-4632-9F1C-46679237B312}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6} = {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24} = {8860606D-6847-F22A-5AED-DF4E0984DD24}\n\tEndProjectSection\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{7C048379-401C-4345-B5E7-BE232DEA8157}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7C048379-401C-4345-B5E7-BE232DEA8157}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7C048379-401C-4345-B5E7-BE232DEA8157}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7C048379-401C-4345-B5E7-BE232DEA8157}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{EE38A326-5DE8-AF09-9EB9-DF0878938783}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{EE38A326-5DE8-AF09-9EB9-DF0878938783}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{EE38A326-5DE8-AF09-9EB9-DF0878938783}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{EE38A326-5DE8-AF09-9EB9-DF0878938783}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{015CB06B-6CAE-209F-E050-21C3ACA5FE9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{015CB06B-6CAE-209F-E050-21C3ACA5FE9F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{06CAADC7-DE5B-47B4-AB2A-E9501459A2D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{06CAADC7-DE5B-47B4-AB2A-E9501459A2D1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AE877E48-6B44-63C2-8EA0-DB58D096B553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AE877E48-6B44-63C2-8EA0-DB58D096B553}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AE877E48-6B44-63C2-8EA0-DB58D096B553}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AE877E48-6B44-63C2-8EA0-DB58D096B553}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}.Debug|Any CPU.Deploy.0 = Debug|Any CPU\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}.Release|Any CPU.Deploy.0 = Release|Any CPU\n\t\t{B8D65F3A-7E54-4632-9F1C-46679237B312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B8D65F3A-7E54-4632-9F1C-46679237B312}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B8D65F3A-7E54-4632-9F1C-46679237B312}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B8D65F3A-7E54-4632-9F1C-46679237B312}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{7C048379-401C-4345-B5E7-BE232DEA8157} = {EDCBFC49-2AEE-4BAF-9368-4409298C52FC}\n\t\t{A78157BA-B754-45F1-969F-D6A513CA0E72} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D}\n\t\t{829FC339-4785-4229-ABA5-53ADB544DA00} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D}\n\t\t{8860606D-6847-F22A-5AED-DF4E0984DD24} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D}\n\t\t{DD10D21A-D131-1D9C-33F9-406046E0C5B0} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D}\n\t\t{EE38A326-5DE8-AF09-9EB9-DF0878938783} = {EDCBFC49-2AEE-4BAF-9368-4409298C52FC}\n\t\t{015CB06B-6CAE-209F-E050-21C3ACA5FE9F} = {985D39A7-5216-4945-8167-2FD0CB387BD8}\n\t\t{06CAADC7-DE5B-47B4-AB2A-E9501459A2D1} = {D36CDFFD-3438-42E4-A7FF-88BA19AC4964}\n\t\t{AE877E48-6B44-63C2-8EA0-DB58D096B553} = {75129C45-FC6F-41B0-A485-07F4A7E031ED}\n\t\t{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D}\n\t\t{B8D65F3A-7E54-4632-9F1C-46679237B312} = {EDCBFC49-2AEE-4BAF-9368-4409298C52FC}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {81A62E71-9E04-4EFE-AD5C-23165375F8EF}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "src/ElectronNET.sln.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:String x:Key=\"/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToExtensionBlock/@EntryIndexedValue\">DO_NOT_SHOW</s:String>\n\t<s:Boolean x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ON_SINGLE_LINE/@EntryValue\">False</s:Boolean>\n\t<s:String x:Key=\"/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CI/@EntryIndexedValue\">CI</s:String>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "src/common.props",
    "content": "<Project>\n  <PropertyGroup>\n    <Version>0.4.1</Version>\n    <PackageNamePrefix>ElectronNET.Core</PackageNamePrefix>\n    <Authors>Gregor Biswanger, Florian Rappl, softworkz</Authors>\n    <Product>Electron.NET</Product>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <PackageProjectUrl>https://github.com/ElectronNET/Electron.NET/</PackageProjectUrl>\n    <RepositoryUrl>$(PackageProjectUrl)</RepositoryUrl>\n    <RepositoryType>git</RepositoryType>\n    <PublishRepositoryUrl>true</PublishRepositoryUrl>\n    <PackageTags>electron aspnetcore</PackageTags>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageReleaseNotes>Changelog: https://github.com/ElectronNET/Electron.NET/blob/main/Changelog.md</PackageReleaseNotes>\n    <PackageIcon>PackageIcon.png</PackageIcon>\n    <DescriptionFirstPart>Building cross platform electron based desktop apps with .NET Core and - optionally - ASP.NET Core.</DescriptionFirstPart>\n    <AssemblyVersion>$(Version)</AssemblyVersion>\n    <FileVersion>$(Version)</FileVersion>\n    <Version>$(Version)$(VersionPostFix)</Version>\n    <InformationalVersion>$(Version)</InformationalVersion>\n  </PropertyGroup>\n</Project>\n\n"
  },
  {
    "path": "src/testEnvironments.json",
    "content": "﻿{\n  \"version\": \"1\",\n  \"environments\": [\n    // See https://aka.ms/remotetesting for more details\n    // about how to configure remote environments.\n    {\n      \"name\": \"WSL Ubuntu\",\n      \"type\": \"wsl\",\n      \"wslDistribution\": \"UbuFresh\"\n    }\n    //{\n    //  \"name\": \"Docker dotnet/sdk\",\n    //  \"type\": \"docker\",\n    //  \"dockerImage\": \"mcr.microsoft.com/dotnet/sdk\"\n    //}\n  ]\n}"
  }
]