[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n*.cs diff=csharp"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [MathewSachin]\ncustom: https://mathewsachin.github.io/Captura/donate\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**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. Windows 8.1]\n - RAM: [e.g. 4GB]\n - CPU: [e.g. i5 2GHz]\n - Graphic Card:\n - Captura Version: [e.g. v8.0.0]\n\n**Additional context**\nAdd any other context about the problem here like FFmpeg Log or error messages.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "content": "---\nname: Question\nabout: For asking questions or discussions\ntitle: ''\nlabels: question\nassignees: ''\n\n---\n\n\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "Please don't send pull-requests for translation. Use the [Crowdin](https://crowdin.com/project/captura) project instead."
  },
  {
    "path": ".gitignore",
    "content": "# Build Output\nbin/\nobj/\n\n# NuGet\n*.nupkg\npackages/\n\n# Visual Studio\n.vs/\n.vscode/\npublish/\nTestResults/\n*.suo\n*.user\n\n# Cake\n/tools\n\n/temp/\n/dist/\n*.pfx\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n### Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n### Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n### Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n### Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n### Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at `mathew DOT sachin DOT git AT outlook DOT com`. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n### Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.4, available at http://contributor-covenant.org/version/1/4"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\n### Star :star:\nThe easiest way to show your support is by starring the repository\n\n### Reporting Bugs\n- Check the [FAQ](https://mathewsachin.github.io/Captura/faq).\n- Check if an issue has already been reported. If so, comment on it and provide further info if any.\n- Follow the `Bug Report` issue template and provide relevant information.\n\n### Get in touch\nYou can chat with us on [Gitter](https://gitter.im/MathewSachin/Captura).\n\n### Contributing Code\n- Make sure to follow the code style followed throughout the project.\n- If you add a new dependency, make sure it is compatible with MIT license.\n  *e.g. GPL is not compatible with MIT license.*\n  Also, add the license file to the **licenses** folder.\n- If you want to add a new feature, discuss it first by opening an issue on GitHub whether it aligns with the goals of the project.\n- If possible, write tests.\n\n### Translation\nDon't send pull-requests for translation.\nUse [Crowdin](https://crowdin.com/project/captura) instead.\n\nIf you want to add a new language, open a discussion on the Crowdin project or a new issue here on GitHub to let me know.\n\n### Testing\nA lot of help is needed in this area.\nWriting tests or just manually testing and reporting or fixing the issues found would be a great help.\n\n### Website\nThe website in written in Angular and resides in a [separate repository](https://github.com/MathewSachin/ng-captura).\n\n### Donation :heavy_dollar_sign:\nYou can donate on [PayPal](https://www.paypal.me/MathewSachin).\n\nYou can see the list of donations on the [website](https://mathewsachin.github.io/Captura/donate).\n\n### Spread the word\nRecommend to others, write reviews, etc."
  },
  {
    "path": "Inno.iss",
    "content": "; Override version before compiling\n;#define MyAppVersion \"6.0.0\"\n\n#define MyAppName \"Captura\"\n#define MyAppPublisher \"Mathew Sachin\"\n#define MyAppURL \"https://MathewSachin.github.io/Captura\"\n#define MyAppExeName \"captura.exe\"\n\n[Setup]\nAppId={{C1670C5E-5042-4300-9491-6BFFF963823F}\nAppName={#MyAppName}\nAppVersion={#MyAppVersion}\nAppVerName={#MyAppName} v{#MyAppVersion}\nAppPublisher={#MyAppPublisher}\nAppPublisherURL={#MyAppURL}\nAppSupportURL={#MyAppURL}\nAppUpdatesURL={#MyAppURL}\nDefaultDirName={pf}\\{#MyAppName}\nDisableProgramGroupPage=yes\nOutputBaseFilename=Captura-Setup\nCompression=lzma\nSolidCompression=yes\nSetupIconFile=src/Captura/Images/Captura.ico\nOutputDir=temp\n\n[Languages]\nName: \"english\"; MessagesFile: \"compiler:Default.isl\"\nName: \"danish\"; MessagesFile: \"compiler:Languages\\Danish.isl\"\nName: \"dutch\"; MessagesFile: \"compiler:Languages\\Dutch.isl\"\nName: \"finnish\"; MessagesFile: \"compiler:Languages\\Finnish.isl\"\nName: \"french\"; MessagesFile: \"compiler:Languages\\French.isl\"\nName: \"german\"; MessagesFile: \"compiler:Languages\\German.isl\"\nName: \"hebrew\"; MessagesFile: \"compiler:Languages\\Hebrew.isl\"\nName: \"italian\"; MessagesFile: \"compiler:Languages\\Italian.isl\"\nName: \"norwegian\"; MessagesFile: \"compiler:Languages\\Norwegian.isl\"\nName: \"polish\"; MessagesFile: \"compiler:Languages\\Polish.isl\"\nName: \"portuguese\"; MessagesFile: \"compiler:Languages\\Portuguese.isl\"\nName: \"russian\"; MessagesFile: \"compiler:Languages\\Russian.isl\"\nName: \"spanish\"; MessagesFile: \"compiler:Languages\\Spanish.isl\"\nName: \"ukrainian\"; MessagesFile: \"compiler:Languages\\Ukrainian.isl\"\n\n[Tasks]\nName: \"desktopicon\"; Description: \"{cm:CreateDesktopIcon}\"; GroupDescription: \"{cm:AdditionalIcons}\"; Flags: unchecked\n\n; Remove Assemblies from previous installation to prevent conflicts\n[InstallDelete]\nType: files; Name: \"{app}\\lib\\*.dll\"\n\n[Files]\nSource: \"dist\\*\"; DestDir: \"{app}\"; Flags: ignoreversion recursesubdirs createallsubdirs\n\n[Icons]\nName: \"{commonprograms}\\{#MyAppName}\"; Filename: \"{app}\\{#MyAppExeName}\"\nName: \"{commondesktop}\\{#MyAppName}\"; Filename: \"{app}\\{#MyAppExeName}\"; Tasks: desktopicon\n\n[Run]\nFilename: \"{app}\\{#MyAppExeName}\"; Description: \"{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}\"; Flags: nowait postinstall skipifsilent"
  },
  {
    "path": "LICENSE.md",
    "content": "﻿MIT License\n\nCopyright (c) 2020 Mathew Sachin\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": "README.md",
    "content": "![Captura](https://mathewsachin.github.io/Captura/assets/Banner.png)\n\n[![Master Build Status](https://img.shields.io/appveyor/ci/MathewSachin/Captura/master.svg?style=flat-square&logo=appveyor)](https://ci.appveyor.com/project/MathewSachin/Captura)\n[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE.md)\n[![Chat](https://img.shields.io/badge/chat-on_gitter-yellow.svg?style=flat-square&logo=gitter)](https://gitter.im/MathewSachin/Captura)\n\n[![Downloads](https://img.shields.io/github/downloads/MathewSachin/Captura/total.svg?style=flat-square)](https://mathewsachin.github.io/Captura/download)\n[![PayPal Donate](https://img.shields.io/badge/donate-PayPal-orange.svg?style=flat-square&logo=paypal)](https://mathewsachin.github.io/Captura/donate)\n[![Crowdin](https://d322cqt584bo4o.cloudfront.net/captura/localized.svg)](https://crowdin.com/project/captura)\n\n&copy; [Copyright 2019](LICENSE.md) Mathew Sachin\n\n:link: <https://mathewsachin.github.io/Captura/>\n\nCapture Screen, WebCam, Audio, Cursor, Mouse Clicks and Keystrokes.\n\n<a href=\"docs/Screenshots\"><img src=\"https://mathewsachin.github.io/Captura/assets/ScreenShots/Home.png\" style=\"max-width: 200px\"></a>\n\n## Features\n\n- Take ScreenShots\n- Capture ScreenCasts (Avi/Gif/Mp4)\n- Capture with/without Mouse Cursor\n- Capture Specific Regions, Screens or Windows\n- Capture Mouse Clicks or Keystrokes\n- Mix Audio recorded from Microphone and Speaker Output\n- Capture from WebCam.\n- Can be used from [Command-line](https://mathewsachin.github.io/Captura/cmdline) (*BETA*).\n- Available in [multiple languages](https://mathewsachin.github.io/Captura/translation)\n- Configurable [Hotkeys](https://mathewsachin.github.io/Captura/hotkeys)\n\n## Installation\n\n[latest]: https://github.com/MathewSachin/Captura/releases/latest\n\nPortable and Setup builds for the latest release can be downloaded from [here][latest].\n\n### Chocolatey\n\n```powershell\nchoco install captura -y\n```\n\n### Dev Builds\n\nSee the [Continuous Integration page](docs/CI.md).\n\n## Docs\n[Build Notes](docs/Build.md) | [System Requirements](docs/System-Requirements.md) | [Contributing](CONTRIBUTING.md)\n\n[ScreenShots](docs/Screenshots) | [Command-line](docs/Cmdline/README.md) | [Hotkeys](https://mathewsachin.github.io/Captura/hotkeys)\n\n[FAQ](docs/FAQ.md) | [Code of Conduct](CODE_OF_CONDUCT.md) | [Changelog](docs/Changelogs/README.md)\n\n[Continuous Integration](docs/CI.md) | [FFmpeg](docs/FFmpeg.md)\n\n## License\n\n[MIT License](LICENSE.md)\n\nCheck [here](licenses/) for licenses of dependencies.\n"
  },
  {
    "path": "SUPPORT.md",
    "content": "# Support\n\n## GitHub Issues\nUse [GitHub issues](https://github.com/MathewSachin/Captura/issues) for Bug Reports, Feature Requests and Questions.\n\n## Gitter\n[![Chat](https://img.shields.io/badge/chat-on_gitter-yellow.svg?style=flat-square)](https://gitter.im/MathewSachin/Captura)\n\n## Mail\nTry to use GitHub Issues instead of mailing, it allows us to track your Feature Requests and Bug Reports better.\n\nUse mail only in cases where personal information is involved.\nPlease specify what you want help with in the mail itself instead of asking for other contact information like phone number or social account details.\n\nAvoid sending mails regarding selling Captura or making a product similar to Captura as those won't be entertained.\n\n`mathew DOT sachin DOT git AT outlook DOT com`"
  },
  {
    "path": "appveyor.yml",
    "content": "version: 0.0.{build}\n\nbranches:\n  except:\n    - l10n_master # Crowdin\n    - gh-pages # Website\n\nimage: Visual Studio 2019\n\nconfiguration:\n- Debug\n- Release\n\n# Used in build.cake\nenvironment:\n  imgur_client_id:\n    secure: Y/2WUSisk7oLSQNY1YzUxw==\n  yt_client_id:\n    secure: CPwUWOhTyZ2IiE+lvVilTKQz1h8sbn7FmkTJvtTlY6mJf2pDlfDhFmhDk1i47M9OPnD4y8a8BlB6yfkpVt/0U/PODAXPzFR0QuOWIfJvltc=\n  yt_client_secret:\n    secure: fsl/BRldjlmEJCroWa0iqw5tAxbGx84BbHT3BpzaeX4=\n  choco_key:\n    secure: h5jOVeiDmjLnF3EotkOhBFJharX/9TWx6OWykiXn30pWSIfVjSvAaCJM1Y48zjXr\n  git_key:\n    secure: eRA1NCG/iXaLTQaBbe2X5Tpje+2Hvk3WOPEP3ZLPFMqW7ZS0ZMTb4UXpw7w59pbc\n\ninstall:\n  - dotnet tool install -g Cake.Tool --version 0.32.1\n  - choco install innosetup -y --no-progress\n\n# Build using Cake\nbuild_script:\n  - ps: >-\n      $tag = $env:APPVEYOR_REPO_TAG_NAME\n\n      if ($tag -ne $null)\n      {\n        $env:prerelease = $tag.Contains(\"-\")\n\n        if ($tag -match \"^build-number-\")\n        {\n          Write-Host \"Build number tag is skipped\"\n          Exit-AppveyorBuild\n        }\n        else \n        {\n          dotnet-cake --target=CI --configuration=$env:CONFIGURATION --build_version=$tag\n        }\n      }\n      else\n      {\n        $version = \"v0.0.\" + $env:APPVEYOR_BUILD_NUMBER\n\n        dotnet-cake --target=CI --configuration=$env:CONFIGURATION --build_version=$version\n      }\n\ntest: off\n\nartifacts:\n  - path: temp/Captura-Portable.zip\n    name: Portable\n  - path: temp/Captura-Setup.exe\n    name: Setup\n  - path: temp/captura.*.nupkg\n    name: Chocolatey\n\ndeploy:\n  - provider: GitHub\n    tag: $(APPVEYOR_REPO_TAG_NAME)\n    release: Captura $(APPVEYOR_REPO_TAG_NAME)\n    prerelease: $(prerelease)\n    description: \"[Changelog](https://github.com/MathewSachin/Captura/tree/master/docs/Changelogs)\"\n    auth_token: $(git_key)\n    artifact: Portable, Setup\n    on:\n      configuration: Release\n      appveyor_repo_tag: true\n\n  - provider: NuGet\n    server: https://chocolatey.org\n    api_key: $(choco_key)\n    artifact: Chocolatey\n    on:\n      configuration: Release\n      appveyor_repo_tag: true"
  },
  {
    "path": "build.cake",
    "content": "#tool nuget:?package=xunit.runner.console&version=2.4.1\n#l \"scripts/backup.cake\"\n#l \"scripts/constants.cake\"\n#l \"scripts/choco.cake\"\n#l \"scripts/apikeys.cake\"\n#l \"scripts/version.cake\"\nusing System.Collections.Generic;\n\n#region Fields\nreadonly var target = Argument(\"target\", \"Default\");\nreadonly var configuration = Argument(\"configuration\", Release);\n#endregion\n\n#region Functions\nvoid PopulateOutput()\n{\n    // Copy License files\n    CopyDirectory(licensesFolder, distFolder + Directory(\"licenses\"));\n\n    var consoleBinFolder = sourceFolder + Directory(\"Captura.Console/bin\") + Directory(configuration);\n    var uiBinFolder = sourceFolder + Directory(\"Captura/bin\") + Directory(configuration);\n    \n    // Copy Languages\n    CopyDirectory(uiBinFolder + Directory(\"Languages\"), distFolder + Directory(\"languages\"));\n\n    // Copy executables and config files\n    CopyFiles(consoleBinFolder.Path + \"/*.exe*\", distFolder);\n    CopyFiles(uiBinFolder.Path + \"/*.exe*\", distFolder);\n\n    // Copy Keymap files\n    CopyDirectory(uiBinFolder + Directory(\"keymaps\"), distFolder + Directory(\"keymaps\"));\n\n    // For Debug builds\n    if (configuration != Release)\n    {\n        // Assemblies, Symbol Files and XML Documentation\n        foreach (var extension in new [] { \".dll\", \".pdb\", \".xml\" })\n        {\n            CopyFiles(consoleBinFolder.Path + \"/*\" + extension, distFolder);\n            CopyFiles(uiBinFolder.Path + \"/*\" + extension, distFolder);\n        }\n    }\n    else\n    {\n        CopyDirectory(consoleBinFolder + Directory(\"lib\"), distFolder + Directory(\"lib\"));\n        CopyDirectory(uiBinFolder + Directory(\"lib\"), distFolder + Directory(\"lib\"));\n    }\n}\n\nvoid PackPortable()\n{\n    // Portable build directories\n    var settingsDir = distFolder + Directory(\"Settings\");\n    var codecsDir = distFolder + Directory(\"Codecs\");\n\n    CreateDirectory(settingsDir);\n    CreateDirectory(codecsDir);\n\n    Zip(distFolder, PortablePath);\n\n    var dirDeleteSettings = new DeleteDirectorySettings {\n        Recursive = true,\n        Force = true\n    };\n\n    DeleteDirectory(settingsDir, dirDeleteSettings);\n    DeleteDirectory(codecsDir, dirDeleteSettings);\n}\n#endregion\n\n#region Setup / Teardown\nSetup(context =>\n{\n    EnsureDirectoryExists(tempFolder);\n    EnsureDirectoryExists(distFolder);\n\n    HandleVersion();\n\n    if (configuration == Release)\n    {\n        EmbedApiKeys();\n    }\n});\n\nTeardown(context =>\n{\n    RestoreBackups();\n});\n#endregion\n\n#region Tasks\nvar buildTask = Task(\"Build\")\n    .Does(() =>\n{\n    MSBuild(slnPath, settings =>\n    {\n        settings.SetConfiguration(configuration)\n            .SetVerbosity(Verbosity.Minimal)\n            .WithTarget(\"Rebuild\")\n            .WithRestore()\n            .UseToolVersion(MSBuildToolVersion.VS2019);\n    });\n});\n\nvar cleanOutputTask = Task(\"Clean-Output\").Does(() => CleanDirectory(distFolder));\n\nvar populateOutputTask = Task(\"Populate-Output\")\n    .IsDependentOn(cleanOutputTask)\n    .IsDependentOn(buildTask)\n    .Does(() => PopulateOutput());\n\nvar packPortableTask = Task(\"Pack-Portable\")\n    .IsDependentOn(populateOutputTask)\n    .Does(() => PackPortable());\n\nvar packSetupTask = Task(\"Pack-Setup\")\n    .IsDependentOn(populateOutputTask)\n    .Does(() =>\n{\n    const string InnoScriptPath = \"Inno.iss\";\n\n    InnoSetup(InnoScriptPath, new InnoSetupSettings\n    {\n        QuietMode = InnoSetupQuietMode.Quiet,\n        ArgumentCustomization = Args => Args.Append($\"/DMyAppVersion={version}\")\n    });\n});\n\nvar packChocoTask = Task(\"Pack-Choco\")\n    .IsDependentOn(packPortableTask)\n    .Does(() => PackChoco());\n\nvar testTask = Task(\"Test\")\n    .IsDependentOn(buildTask)\n    .Does(() => XUnit2(sourceFolder + File($\"Tests/bin/{configuration}/**/Captura.Tests.dll\")));\n\nvar defaultTask = Task(\"Default\")\n    .IsDependentOn(packPortableTask)\n    .IsDependentOn(packSetupTask)\n    .IsDependentOn(packChocoTask);\n#endregion\n\nTask(\"CI\")\n    .IsDependentOn(testTask)\n    .IsDependentOn(packPortableTask)\n    .IsDependentOn(packSetupTask)\n    .IsDependentOn(packChocoTask)\n    .Does(() => { });\n\n// Start\nRunTarget(target);"
  },
  {
    "path": "choco/captura.nuspec",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd\">\n  <metadata>\n    <id>captura</id>\n    <version>8.0.0</version>\n    <title>Captura</title>\n    <authors>Mathew Sachin</authors>\n    <projectUrl>https://MathewSachin.github.io/Captura</projectUrl>\n    <projectSourceUrl>https://github.com/MathewSachin/Captura</projectSourceUrl>\n    <iconUrl>https://raw.githubusercontent.com/MathewSachin/Captura/master/src/Captura/Images/Logo.png</iconUrl>\n    <licenseUrl>https://github.com/MathewSachin/Captura/blob/master/LICENSE.md</licenseUrl>\n    <packageSourceUrl>https://github.com/MathewSachin/Captura/tree/master/choco</packageSourceUrl>\n    <bugTrackerUrl>https://github.com/MathewSachin/Captura/issues</bugTrackerUrl>\n    <docsUrl>https://MathewSachin.github.io/Captura</docsUrl>\n    <mailingListUrl>https://gitter.im/MathewSachin/Captura</mailingListUrl>\n    <copyright>(c) 2018 Mathew Sachin</copyright>\n    <tags>captura screen capture recording loopback screenshot screencast</tags>\n    <summary>Capture Screen/Audio/Cursor/Clicks/Keystrokes</summary>\n    <description>\nCaptura is an application to capture Screen/Audio/Cursor/Clicks/Keystrokes.\n    </description>\n    <releaseNotes>[Changelog](https://MathewSachin.github.io/Captura/changelog)</releaseNotes>\n  </metadata>\n  <files>\n    <file src=\"tools\\**\" target=\"tools\" />\n  </files>\n</package>\n"
  },
  {
    "path": "choco/tools/chocolateyinstall.ps1",
    "content": "﻿$params = @{\n    'PackageName' = 'Captura';\n    'Url' = \"https://github.com/MathewSachin/Captura/releases/download/$tag/Captura-Portable.zip\";\n    'UnzipLocation' = \"$(Split-Path -parent $MyInvocation.MyCommand.Definition)\";\n    'Checksum' = $checksum;\n    'ChecksumType' = 'sha256';\n};\n\nInstall-ChocolateyZipPackage @params"
  },
  {
    "path": "crowdin.yml",
    "content": "files:\n  - source: /src/Captura.Loc/Languages/en.json\n    translation: /src/Captura.Loc/Languages/%two_letters_code%.json\n    languages_mapping:\n      two_letters_code:\n        zh-CN: zh-CN\n        zh-TW: zh-TW\n        pt-BR: pt-BR"
  },
  {
    "path": "docs/Acknowledgements.md",
    "content": "# Acknowledgements\n\n## Tools and Services\n\n### Resharper\nKudos to Jetbrains for providing open-source license for [Resharper Ultimate](https://www.jetbrains.com/resharper/).\nResharper makes development much intutive and easier. You should really check it out.\nIf you become a regular contributor to Captura, you may request for the Resharper license.\n\n### Crowdin\nGreat thanks to [Crowdin](https://crowdin.com/) for providing open-source license.\nThe translation for Captura is done on Crowdin.\nAlso, thanks to everyone who contributed the translations.\n\n### AppVeyor\nWe use [AppVeyor](https://www.appveyor.com/) for Continuous Integration. The build and release processes run there.\nIt's free for open-source projects and especially good for .NET projects.\n\n### GitHub\nI can't thank [GitHub](https://github.com/) enough for being an open platform for developers.\nThe source code and the website are both hosted here.\n\n### Cake Build\n[Cake](https://cakebuild.net/) allows us to write our build scripts in C# instead of using other scripting languages.\n\n### Visual Studio Community\n[Visual Studio IDE](https://visualstudio.microsoft.com/) for free for open-source and small organisations.\n\n### Visual Studio Code\n[Visual Studio Code](https://code.visualstudio.com) is an open-source text editor used to build the website and write the documentation.\n\n### Inno Setup\nSetup files for Captura are built using [Inno Setup](http://www.jrsoftware.org/isinfo.php).\n\n## Libraries\n\n### CommandLineParser\n[GitHub](https://github.com/commandlineparser/commandline/) -\n[MIT License](https://github.com/commandlineparser/commandline/blob/master/License.md)\n\n```\nNuGet Install CommandLineParser\n```\n\n### CroppingAdorner\n[CodeProject Article](https://www.codeproject.com/Articles/23158/A-Photoshop-like-Cropping-Adorner-for-WPF) -\n[Code Project Open License (CPOL)](https://www.codeproject.com/info/cpol10.aspx)\n\n### DirectShowLib\n[SourceForge](http://directshownet.sourceforge.net/)\n\n### FFmpeg\n[Website](https://ffmpeg.org/)\n\n### MouseKeyHook\n[GitHub](https://github.com/gmamaladze/globalmousekeyhook) -\n[MIT License](https://github.com/gmamaladze/globalmousekeyhook/blob/vNext/LICENSE.txt)\n\n```\nnuget install MouseKeyHook\n```\n\n### MUI.Extended.Toolkit\n[GitHub](https://github.com/samoatesgames/mui.extended.toolkit) -\n[MIT License](https://github.com/samoatesgames/mui.extended.toolkit/blob/master/LICENSE)\n\n### MUI\n[GitHub](https://github.com/firstfloorsoftware/mui) -\n[MS-PL](https://github.com/firstfloorsoftware/mui/blob/master/LICENSE.md)\n\n### NAudio\n[GitHub](https://github.com/naudio/NAudio) -\n[MS-PL](https://github.com/naudio/NAudio/blob/master/license.txt)\n\n### Newtonsoft.Json\n[Website](https://www.newtonsoft.com/json) -\n[GitHub](https://github.com/JamesNK/Newtonsoft.Json) -\n[MIT License](https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md)\n\n### Ooki.Dialogs\n[Website](http://www.ookii.org/software/dialogs/)\n\n### ReactiveProperty\n[GitHub](https://github.com/runceel/ReactiveProperty)\n\n### ScreenToGif\n[Website](https://www.screentogif.com/)\n\n### SharpAvi\n[GitHub](https://github.com/baSSiLL/SharpAvi)\n\n### SharpDX\n[GitHub](https://github.com/sharpdx/SharpDX)\n\n### WPFNotifyIcon\n[Website](http://www.hardcodet.net/wpf-notifyicon)\n\n### WpfToolkit\n[GitHub](https://github.com/xceedsoftware/wpftoolkit)\n\n### Media Foundation .NET\n[SourceForge](http://mfnet.sourceforge.net/)\n\n### ReactiveX\n[GitHub](https://github.com/dotnet/reactive)\n"
  },
  {
    "path": "docs/Build.md",
    "content": "# Building\n\n## Setting up locally\n\n### Prerequisites\n- Visual Studio 2019 or newer with .NET desktop development workload.\n- .Net Core 2.1 or greater\n- Cake tool  \n  Install: `dotnet tool install -g Cake.Tool --version 0.32.1`\n- Some features have other specific requirements, see [here](https://mathewsachin.github.io/Captura/sys-req).\n\n### Steps\n1. Clone  \n   `git clone https://github.com/MathewSachin/Captura.git`\n2. Setup Api Keys. These are loaded from environment variables during development and embedded into the app on production builds.\n   \n   Environment Variable | Description\n   ---------------------|-------------\n   imgur_client_id      | Imgur Client Id\n   yt_client_id         | YouTube Client Id\n   yt_client_secret     | YouTube Client Secret\n\n   Imgur credentials are only required if you want to upload to Imgur. See [here](https://apidocs.imgur.com/) for more info.\n\n   YouTube credentials are only required if you want to upload to YouTube. See [here](https://developers.google.com/youtube/registering_an_application) for more info.\n\n3. Download FFmpeg from within the app or from https://ffmpeg.zeranoe.com/builds/ or use a custom build.\n4. Now, you're good to go. You can build using Visual Studio or the [cake script](Cake.md)."
  },
  {
    "path": "docs/CI.md",
    "content": "# Continuous Integration\n\nWe use [Appveyor](https://www.appveyor.com/) for CI.\nWhen a commit is pushed to the GitHub repository, AppVeyor clones the repo and builds and tests it using the Cake build script.\nIf it is a tag build, the release is deployed to GitHub Releases as a draft and to Chocolatey.\n\n### Getting dev builds\n\n> Dev builds can be unstable and should be used for testing purposes only.\n\n1. Go to [AppVeyor project](https://ci.appveyor.com/project/MathewSachin/Captura/branch/master) page.\n\n2. Select Build Configuration: **Debug** or **Release**.\n\n   ![img](https://mathewsachin.github.io/Captura/assets/dev-builds/1.png)\n\n3. Open **Artifacts** tab.\n\n   ![img](https://mathewsachin.github.io/Captura/assets/dev-builds/2.png)\n\n4. Download the Portable or Setup version according to your need.\n\n   ![img](https://mathewsachin.github.io/Captura/assets/dev-builds/3.png)"
  },
  {
    "path": "docs/Cake.md",
    "content": "# Cake build script\n\n### Installing Cake\n.NET Core 2.1 is required.\n\n```\ndotnet tool install -g Cake.Tool --version 0.32.1\n```\n\n### Running the build script\n```\ndotnet-cake\n```\n\n### Arguments\n\nOption         | Description\n---------------|--------------\n-build_version | Build version. Should be like v9.0.0 for stable and CI builds and like v9.0.0-beta3 for prerelease builds. AssemblyInfo.cs files are updated based on this value during build.\n-configuration | Configuration: Release or Debug\n-target        | The Task to run in the build script. See build.cake\n\n```\ndotnet-cake --target=CI --configuration=Release\n```"
  },
  {
    "path": "docs/Changelogs/README.md",
    "content": "# Changelogs\n\n- [v9.0.0](v9.0.0.md)\n- [v8.0.0](v8.0.0.md)\n- [v7.0.1](v7.0.1.md)"
  },
  {
    "path": "docs/Changelogs/v7.0.1.md",
    "content": "# v7.0.1\n\n**Fix:** FFmpeg download link gives 404."
  },
  {
    "path": "docs/Changelogs/v8.0.0.md",
    "content": "# v8.0.0\n\n> This changelog is incomplete.\n\n### Audio / Video Sources\n- Stop Window capture when Window is closed.\n- **Fix:** Mouse cursor position is wrong after moving region selector.\n- **Fix:** Unable to resize Region Selector after stopping recording.\n- Desktop Duplication is supported with Variable Frame Rate Gif.\n- **Fix:** Desktop Duplication recording does not crash when Screen enters non-recordable mode. e.g. Sign-in screen.\n- Added an option to playback recorded audio in real-time in Config | Extras.\n- Record and ScreenShot buttons on Region Selector.\n- Added Window picker and Screen picker which prompt for selector on starting recording or taking screenshot.\n- More than 2 audio sources can be simultaneously recorded.\n- Audio sources can be changed during recording. A checkbox next to the Audio heading determines whether audio will be recorded.\n- Shows Error Message when bass.dll or bassmix.dll is not present.\n- Hide when Recording option is configured on Region Selector itself.\n- Refresh retains selected Audio/Video sources/codecs and Webcam.\n- Basic drawing support in Region Selector.\n\n### Preview\n- Added option to Preview while recording.\n- Supports full screen view.\n\n### Overlays\n- Overlays are now configured on a separate window.\n- Overlays can be positioned by dragging boxes over a Background on the window.\n- Separate colors for Right and Middle mouse click overlays.\n- Support for custom image overlays.\n- Overlay customization from UI is used in Console.\n- Option to display Mouse Pointer Overlay to make easier to track Mouse Pointer.\n- Added minimal mouse click animation.\n- Elapsed is separated from TextOverlays and can be toggled from Main View.\n\n### FFmpeg\n- Option to resize FFmpeg output video size.\n- FFmpeg Log maintains multiple logs.\n- FFmpeg Log copies complete output to clipboard.\n- Multiple Custom FFmpeg Codecs.\n- Increased FFmpeg thread_queue_size\n- Ensure previous frame is written when writing asynchronously.\n\n### Hotkey Window\nSeparate window to manage hotkeys with option to add, delete or edit action and keys.\n\n### Image Editor\n- Added a minimal image editor.\n- Added a new ScreenShot target: Editor.\n\n### Image Cropper\nAdded option to crop images.\n\n### Audio / Video Trimmer\nAdded option to trim Audio and Video.\n\n### Translation\nAdded new translations:\n\n- Japanese\n- Chinese (Simplified)\n- Chinese (Traditional)\n\n### Other\n- **Fix:**captura shot failing for fullscreen screenshots.\n- **Fix:** Main window webcam preview position on high DPI.\n- Duration is considered after Start Delay has elapsed.\n- Duration and Start Delay are stored in Settings.\n- Added option to use System Proxy.\n- **Fix:** Mouse Cursor moves slowly when recording from Command-line\n- Webcam capture support from Command-line.\n- Option to Minimize to System Tray on Startup.\n- Option to Minimize to System Tray when Closed.\n- Add a Translator window to aid in translation. Can be opened from About tab.\n- More icons in the UI.\n- Multiple selectable Screenshot Save Locations.\n- Display Licenses in a Window.\n- Notification Stack\n- Added an Exception Dialog.\n- Stop Recorder when Frames are not being writen. This happens when either the FrameRate is too high or a codec is slow. No of frames to be written are checked with a maximum value to determine whether to stop recording. This helps prevent crash from 100% RAM usage and causing the system to hang.\n- Ability to delete uploaded images from Imgur"
  },
  {
    "path": "docs/Changelogs/v9.0.0.md",
    "content": "# v9.0.0\n\n> Not released yet!\n\n- Translations updated.\n- Added Portuguese, Brazilian translation.\n- Fallback to NAudio for audio when BASS is not available.\n- Update check in footer.\n- Open Webcam preview window by clicking on small preview.\n- **Fix:** Recording failing due to `System can't keep up with the Recording. Frames are not being written. Retry again or try with a smaller region, lower Frame Rate or another Codec.`\n- Replaced the Gif encoder with FFmpeg Gif (Post-Processing) encoder.\n- Discard writer renamed to Preview Only and automatically shows Preview window on starting recording.\n- Use system confirmation dialog when deleting from recent list.\n- Added YouTube upload feature. Can be used from recent list context menu.\n- Remove notifications when notification stack hides.\n- Region dimension boxes on Main UI.\n- FFmpeg Log can be opened from Home page.\n- PasswordBox for Proxy and Streaming keys.\n- Region Selector can be Moved/Resized using Keyboard.\n- **Fix:** Window position is not remembered.\n- **Fix:** Remove 5 fps limit on Preview window.\n- **Fix:** Arrow and Only Audio icons.\n- **Fix:** weird behaviour of Region Selector border.\n- **Fix:** DPI issues when saving from Image Editor.\n- **Fix:** BASS WaveFormat for SeparateAudioFilePerSource.\n- **Fix:** Smooth rendering of mouse clicks.\n- **Fix:** Streaming FrameRate was always set to 10.\n- Added Webcam only mode.\n- Settings, Codecs folders in AppDir for portability.\n- Support `%CAPTURA_PATH%` to point to app directory in FFmpeg, Output and Settings paths.\n- Change `Minimize on Capture Start` to minimize to tray.\n- Show a simpler Error Window on Exceptions."
  },
  {
    "path": "docs/Choco.md",
    "content": "# Chocolatey\nChocolatey package is created using the Cake build script and deployed on tag builds by AppVeyor.\n\n### Installation\n```\nchoco install captura -y\n```"
  },
  {
    "path": "docs/Cmdline/Arg-Source.md",
    "content": "# Using the source Argument\n\n## Desktop\nUse the `desktop` parameter to capture the entire Desktop **(Default)**.\nWorks with both `captura-cli start` and `captura-cli shot`.\nThis is the default option, so is as good as not using this option.\n\ne.g.\n\n```\ncaptura-cli start --source desktop\n```\n\n## Region\nUse Left, Top, Width and Height resp. as comma separated values to represent the region to capture.\nWorks with both `captura-cli start` and `captura-cli shot`.\nThe dimensions of the region must be even. If not, they are decreased by 1 as required.\n\ne.g.\n\n```\ncaptura-cli shot --source 100,100,300,400\n```\n\n## Screen\nUse `screen:<index>` as the argument. `index` is a zero-based index identifying the screen.\n\nWorks with both `captura-cli start` and `captura-cli shot`.\n\nYou can use `captura-cli list` to check screen indices.\n\ne.g.\n\n```\ncaptura-cli start --source screen:1\n```\n\n## No Video\nUse `none` for No Video.\n\nAvailable only with `captura-cli start`.\n\nCan be used for audio only recording.\n\ne.g. Record only the speaker output.\n\n```\ncaptura-cli start --source none --speaker 0\n```\n\n## Window\nUse `win:<hWnd>` as the argument. `hWnd` is handle of the window.\n\nWhen using with `captura-cli start`, the window handle must be in the `captura-cli list` output.\n\nYou can use `captura-cli list` to check visible window handles.\n\n## Webcam\nUse `webcam` as the argument to capture only the webcam.\nCan only work with `captura-cli start`.\n\nUse the `--webcam` argument to set the webcam.\nYou can use `captura-cli list` to check available webcams.\n\ne.g.\n\n```\ncaptura-cli start --source webcam --webcam 0\n```"
  },
  {
    "path": "docs/Cmdline/README.md",
    "content": "# Command-line\n\nProject      | Executable\n-------------|----------------\nUI           | captura.exe\nCommand-line | captura-cli.exe\n\nWe use the [CommandLineParser](https://nuget.org/packages/CommandLineParser) NuGet package.\n\nThe console projects uses default settings with a few modifications and does not save settings.\n\n> Command-line support is not very stable. Please report any bugs you find.\n\n### Why a separate Console app?\nThere are many issues related to using a WPF application as a console app.\n\n- WPF applications don't block the console. So, we cannot use it for scenarios like wait till capture is completed.\n- Writing to console does not work by default\n- If `AttachConsole` is used, the written content interferes with console prompt.\n- And more ...\n\n### Command-line parameters for UI version\n\nArgument     | Description\n-------------|----------------------------------\n--reset      | Reset all Settings\n--tray       | Starts minimized to System Tray\n--no-persist | Don't Save any changes in Settings\n--no-hotkey  | Don't Register Hotkeys.\n--settings   | Custom settings folder\n\ne.g. Start captura minimized to tray\n\n```\ncaptura --tray\n```\n\n### Implemented Verbs\n\n- [list](Verb-List.md)\n  List available Screens, Windows, Audio Sources, Webcams, etc.\n- [start](Verb-Start.md)\n  Start a Recording\n- [shot](Verb-Shot.md)\n  Take a ScreenShot\n- [ffmpeg](Verb-FFmpeg.md)  \n  Allows installation of ffmpeg from command-line.\n- help  \n  Provides help on using the console app.\n- version  \n  Prints the version of the console app."
  },
  {
    "path": "docs/Cmdline/Verb-FFmpeg.md",
    "content": "# Verb: FFmpeg\nCan be used to install FFmpeg\n\ne.g. Install FFmpeg to Codecs directory\n\n```\ncaptura-cli ffmpeg --install Codecs\n```"
  },
  {
    "path": "docs/Cmdline/Verb-List.md",
    "content": "# Verb: list\nDisplays the following information:\n\n- Version\n- If FFmpeg is available\n- FFmpeg encoders\n- If SharpAvi is available\n- SharpAvi encoders\n- If MouseKeyHook is available\n- Visible Windows with hWnd\n- Screens if there are more than 1\n- Available Microphones\n- Available Speaker output sources\n\n```\ncaptura list\n```"
  },
  {
    "path": "docs/Cmdline/Verb-Shot.md",
    "content": "# Verb: shot\nTakes a screenshot\n\nArgument         | Description\n-----------------|--------------------------------------------\n`--cursor`       | Include cursor in the screenshot\n`--source`       | The source to take screenshot of. See [here](Arg-Source.md).\n`-f` or `--file` | Output file path.\n\ne.g. Take a screenshot containing cursor.\n\n```\ncaptura-cli shot --cursor\n```"
  },
  {
    "path": "docs/Cmdline/Verb-Start.md",
    "content": "# Verb: start\nStarts Recording.\n\nThere are two modes.\n\nWhen Length is specified, recording runs until specified Length.\nWhen Length is not specified, press q to quit message is displayed.\n\nArgument              | Description\n----------------------|-------------------------------------------------------------------------\n`--cursor`            | Include cursor\n`--keys`              | Include keystrokes\n`--clicks`            | Include mouse clicks\n`--delay`             | Delay before starting recording (in ms)\n`-t` or `--length`    | Length of recording (in s)\n`--source`            | The source to record from. See [here](Arg-Source.md).\n`--mic`               | The microphone index to use. (-1 = none (Default)) (0 is first device).\n`--speaker`           | The speaker output index to use. (-1 = none (Default)) (0 is first device).\n`--webcam`            | Webcam to use. (-1 = none (Default)) (0 is first webcam).\n`-r` or `--framerate` | Frame Rate (Default is 10).\n`--encoder`           | The video encoder to use. See below.\n`--vq`                | Video Quality (1 to 100) (Default is 70).\n`--aq`                | Audio Quality (1 to 100) (Default is 50).\n`-f` or `--file`      | Output file path.\n`-y`                  | Overwrite existing file.\n`--replay`            | Replay recording. Specify duration in seconds as parameter. e.g. `--replay 20`.\n\ne.g. Record 10 seconds with cursor and keystrokes and audio from first speaker output.\n\n```\ncaptura-cli start --length 10 --cursor --keys --speaker=0\n```\n\n## Using the Encoder argument\n\nBy default, SharpAvi Motion JPEG encoder is used.\n\n### SharpAvi\nUse `sharpavi:<index>` as argument. `index` is a zero-based index identifying the encoder.\n\nYou can use `captura-cli list` to check encoder indices.\n\ne.g.\n\n```\ncaptura-cli start --encoder sharpavi:0\n```\n\n## Media Foundation\nUse `mf` as argument.\n\ne.g.\n\n```\ncaptura-cli start --encoder mf\n```\n\n### FFmpeg\nUse `ffmpeg:<index>` as argument. `index` is a zero-based index identifying the encoder.\n\nYou can use `captura-cli list` to check encoder indices.\n\ne.g.\n\n```\ncaptura-cli start --encoder ffmpeg:0\n```\n\n### Stream\nUse `stream:<url>` as argument. `url` is the rtmp url of the streaming service.\n\ne.g. Stream to Twitch\n\n```\ncaptura-cli start --encoder stream:rtmp://live.twitch.tv/app/TWITCH_KEY\n```\n\n### Steps\nUse `steps:video` and `steps:images` as `encoder` for Steps recording mode.\n\n#### Record steps to video (avi)\n\n```\ncaptura-cli start --encoder steps:video\n```\n\n#### Record steps to a folder containing images (png)\n\n```\ncaptura-cli start --encoder steps:images\n```"
  },
  {
    "path": "docs/Directories.md",
    "content": "# Directory Structure\n\n- **src**\n  Contains the source code. It is organized into multiple [projects](Projects.md).\n\n- **temp**\n  Used for temporary files generated when building using the Cake script.\n\n- **dist**\n  Cake build output folder.\n\n- **choco**\n  Files for generating the Chocolatey package.\n\n- **licenses**\n  Licenses of dependencies.\n\n- **scripts**\n  Build scripts used by `build.cake`.\n\n- **tools**\n  Created by Cake build to store its dependencies."
  },
  {
    "path": "docs/FAQ.md",
    "content": "# Frequently Asked Questions\n\n## Will Captura support Linux or Mac?\nCaptura is written using .NET Framework, which at present, is supported only on Windows.\n\nSoftware written using .NET Framework can work on Linux and Mac using Mono but the native calls and UI pose a problem to that.\n\nAlso, the recently released .Net Core only has support for console applications.\n\n## Does Captura support DirectX Game Video Recording?\nSome games can be recorded when running on Windows 8 and above. In Captura v8.0.0 there was a separate `Desktop Duplication` option which can also record games which support that. From v9.0.0, `Desktop Duplication` is the default mode.\n\n## Why is maximum frame rate 30fps?\nCaptura is not very fast on low-end systems. This limit on framerate is a protection against Captura consuming all of your CPU/Memory/Disk and causing your system to hang.\n\nStarting from v8.0.0, you can remove this limitation by going to Config / Extras / Remove FPS Limit.\n\nFor reference, Captura can capture 1920x1080 screen at 40fps on my system without audio using FFmpeg x264 codec. My system specifications: 8GB RAM DDR4, Intel i5 6th Gen CPU 2.3 GHz, Windows 10.\n\n## Why is the length of captured video shorter than recording duration?\nThis happens when Captura drops frames when your system can't keep with the specified frame rate. Try using a lower value of framerate, faster codec or smaller region.\n\n## Why does Captura run out of resources (high memory/CPU/disk usage) during recording?\nAtleast 2 GHz CPU and 4 GB RAM are recommended.\n\nThis may happen if frames are not being captured as fast as the framerate set. Try a lower value of framerate, faster codec or smaller region. Also, try terminating unnecessary applications running in background using Task Manager. We admit that the technology employed in Captura is not fast.\n\n## Why does my Antivirus say that Captura is virus infected?\nCaptura is virus-free. It does not include any spam, adware or spyware.\n\nIt is probably due to the keystrokes capture feature being mistaken for a keylogger."
  },
  {
    "path": "docs/FFmpeg.md",
    "content": "# FFmpeg\n\n> It is recommended to always download the latest version of FFmpeg using FFmpeg Downloader. Older versions of FFmpeg can cause unexpected behaviour.\n\n[FFmpeg](http://ffmpeg.org/) is an open-source cross-platform solution to record, convert and stream audio and video.\nIt adds support for more output formats like **H.264** for Video and **Mp3**, **AAC** etc. when capturing **Only Audio**.\n\nFFmpeg is configured on the **FFmpeg** section in the **Configure** tab.\n\nDue to its large size (approx. 30MB), it is not included in the downloads.\nIf you already have FFmpeg on your system, you can just set the path to the folder containing it.\nIf it is installed globally (available in PATH), you don't have to do anything.\nIf you don't have FFmpeg or want to update, use the inbuilt **FFmpeg Downloader**.\nFFmpeg needs to be downloaded only once.\n\nIn cases where the **FFmpeg Downloader** fails, please download manually from <https://ffmpeg.zeranoe.com/builds/> and set FFmpeg folder in `Configure | FFmpeg`.\n\nIf you don't want to use FFmpeg, you can switch to `SharpAvi`."
  },
  {
    "path": "docs/Portable.md",
    "content": "# Portable\n\nStarting from v9.0.0, for portable builds:\n\n1. Settings are stored in `Settings` folder in app folder by default.\n   Deleting the `Settings` folder will cause settings to be saved at `%AppData%\\Captura`.\n   This can be overridden by using the `--settings` command-line argument.\n\n2. FFmpeg is downloaded into `Codecs` folder in app folder by default.\n   Deleting the `Codecs` folder will cause FFmpeg to be downloaded into `%LocalAppData%\\Captura`.\n   This can be overriden from UI.\n\nWhen setting FFmpeg folder, Settings folder or output folder, `%CAPTURA_PATH%` can be used to refer to the app folder.\n\ne.g. `%CAPTURA_PATH%/Settings` means `Settings` folder in app folder."
  },
  {
    "path": "docs/Projects.md",
    "content": "# Project Structure\n\n## Base\n`Captura.Base` contains common interfaces and base classes. This project is referenced by all other projects.\n\n## Localization\n`Captura.Loc` contains the localization code.\n\n## Audio\n`Captura.Audio` contains the audio interfaces which are implemented by specific libraries like `Captura.NAudio`.\n\n## Screna, Core\n`Screna` and `Captura.Core` projects contain the bulk of the code and are depended on by both UI and Console projects.\n\n## Windows\n`Captura.Windows` conatins code that is completely specific to the Windows OS.\n\n## Console\n`Captura.Console` builds the console application.\n\n## View Core\n`Captura.ViewCore` project contains View models and is depended on by the UI project.\n\n## UI\n`Captura` is a WPF project containing the UI.\n\n## Other\nThe remaining projects add specific features like Imgur, SharpAvi, FFmpeg, etc."
  },
  {
    "path": "docs/README.md",
    "content": "# Docs\n\n> INCOMPLETE. WORK IN PROGRESS. BEING WRITTEN FOR v9.0.0 WHICH IS YET TO BE RELEASED."
  },
  {
    "path": "docs/Screenshots/Dark.md",
    "content": "# Screenshots - Dark Theme\n\n## Home\n\n![Home](https://mathewsachin.github.io/Captura/assets/ScreenShots/Home-Dark.png)\n\n## Collapsed\n\n![Collapsed](https://mathewsachin.github.io/Captura/assets/ScreenShots/Collapsed-Dark.png)\n\n## Recent\n\n![Recent](https://mathewsachin.github.io/Captura/assets/ScreenShots/Recent-Dark.png)\n\n## Configure\n\n![Configure](https://mathewsachin.github.io/Captura/assets/ScreenShots/Configure-Dark.png)\n\n## Hotkeys\n\n![Hotkeys](https://mathewsachin.github.io/Captura/assets/ScreenShots/Hotkeys-Dark.png)\n\n## FFmpeg\n\n![FFmpeg](https://mathewsachin.github.io/Captura/assets/ScreenShots/FFmpeg-Dark.png)\n\n## Overlays\n\n![Overlays](https://mathewsachin.github.io/Captura/assets/ScreenShots/Overlays-Dark.png)\n\n## About\n\n![About](https://mathewsachin.github.io/Captura/assets/ScreenShots/About-Dark.png)"
  },
  {
    "path": "docs/Screenshots/Light.md",
    "content": "# Screenshots - Light Theme\n\n## Home\n\n![Home](https://mathewsachin.github.io/Captura/assets/ScreenShots/Home.png)\n\n## Collapsed\n\n![Collapsed](https://mathewsachin.github.io/Captura/assets/ScreenShots/Collapsed.png)\n\n## Recent\n\n![Recent](https://mathewsachin.github.io/Captura/assets/ScreenShots/Recent.png)\n\n## Configure\n\n![Configure](https://mathewsachin.github.io/Captura/assets/ScreenShots/Configure.png)\n\n## Hotkeys\n\n![Hotkeys](https://mathewsachin.github.io/Captura/assets/ScreenShots/Hotkeys.png)\n\n## FFmpeg\n\n![FFmpeg](https://mathewsachin.github.io/Captura/assets/ScreenShots/FFmpeg.png)\n\n## Overlays\n\n![Overlays](https://mathewsachin.github.io/Captura/assets/ScreenShots/Overlays.png)\n\n## About\n\n![About](https://mathewsachin.github.io/Captura/assets/ScreenShots/About.png)"
  },
  {
    "path": "docs/Setup.md",
    "content": "# Setup\n\nWe use [Inno Setup](http://www.jrsoftware.org/isinfo.php) to create the installer for Captura."
  },
  {
    "path": "docs/System-Requirements.md",
    "content": "# System Requirements\nSystem Requirements for the app to run.\n\n## Operating System\nWindows 10 is recommended.  \nAtleast Windows 7 is required.  \nIf you are on Window 7, make sure *Aero* is enabled.\n\nScreen recording is more efficient on Windows 8 and above as compared to Windows 7.\n\n## Hardware\n- 2 GHz CPU (Recommended)\n- 4 GB RAM (Recommended)\n\n## .NET Framework\n[.NET Framework v4.7.2 Runtime](https://dotnet.microsoft.com/download/dotnet-framework/net472) is required.\n\n## FFmpeg\nThe app automatically prompts to download FFmpeg if it is not already present on your system.\n\n## Intel QSV\nUsing the **FFmpeg Intel QSV HEVC** encoder requires the processor to be **Skylake (6th generation)** or later.\n\n## NVenc\nSee if your GPU supports NVenc for H.264 and H.265 in the [Support Matrix](https://developer.nvidia.com/video-encode-decode-gpu-support-matrix.)\n\n## Lagarith codec\nLagarith codec can be used with SharpAvi.\n\n- Install the codec from its [official website](https://lags.leetcode.net/codec.html).\n- Make sure it is configured to use RGB mode.\n- Make sure that Null Frames is disabled.\n\nRGB mode and Null Frames can be configured from the registry:\n\n##### HKEY_CURRENT_USER\\Software\\Lagarith:\n- Mode = RGB\n- NullFrames= 2294784"
  },
  {
    "path": "licenses/Captura, Screna.txt",
    "content": "The MIT License\n\n(c) Copyright 2018 Mathew Sachin.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "licenses/CommandLineParser.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2005 - 2015 Giacomo Stelluti Scala & Contributors\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\nall copies 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\nTHE SOFTWARE."
  },
  {
    "path": "licenses/CroppingAdorner.txt",
    "content": "Code Project Open License (CPOL)\n\nhttps://www.codeproject.com/info/cpol10.aspx\n\nhttps://www.codeproject.com/Articles/23158/A-Photoshop-like-Cropping-Adorner-for-WPF"
  },
  {
    "path": "licenses/DirectShowLib.txt",
    "content": "\t\t  GNU LESSER GENERAL PUBLIC LICENSE\n\t\t       Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL.  It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it.  You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n  When we speak of free software, we are referring to freedom of use,\nnot price.  Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n  To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights.  These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library.  Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\n\n\n  Finally, software patents pose a constant threat to the existence of\nany free program.  We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder.  Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n  Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License.  This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License.  We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n  When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library.  The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom.  The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n  We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License.  It also provides other free software developers Less\nof an advantage over competing non-free programs.  These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries.  However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n  For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard.  To achieve this, non-free programs must be\nallowed to use the library.  A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries.  In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n  In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software.  For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n  Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\n\n\n\t\t  GNU LESSER GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n  \n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\n\n\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\n\n\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\n\n\n  6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Use a suitable shared library mechanism for linking with the\n    Library.  A suitable mechanism is one that (1) uses at run time a\n    copy of the library already present on the user's computer system,\n    rather than copying library functions into the executable, and (2)\n    will operate properly with a modified version of the library, if\n    the user installs one, as long as the modified version is\n    interface-compatible with the version that the work was made with.\n\n    c) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    d) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    e) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\n\n\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\n\n\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\n\n\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\n\n\n           How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Lesser General Public\n    License as published by the Free Software Foundation; either\n    version 2.1 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!\n\n"
  },
  {
    "path": "licenses/FFMpeg.txt",
    "content": "                  GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL.  It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it.  You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n  When we speak of free software, we are referring to freedom of use,\nnot price.  Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n  To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights.  These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library.  Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\f\n  Finally, software patents pose a constant threat to the existence of\nany free program.  We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder.  Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n  Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License.  This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License.  We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n  When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library.  The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom.  The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n  We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License.  It also provides other free software developers Less\nof an advantage over competing non-free programs.  These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries.  However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n  For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard.  To achieve this, non-free programs must be\nallowed to use the library.  A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries.  In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n  In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software.  For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n  Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\f\n                  GNU LESSER GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n\n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\f\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n  6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Use a suitable shared library mechanism for linking with the\n    Library.  A suitable mechanism is one that (1) uses at run time a\n    copy of the library already present on the user's computer system,\n    rather than copying library functions into the executable, and (2)\n    will operate properly with a modified version of the library, if\n    the user installs one, as long as the modified version is\n    interface-compatible with the version that the work was made with.\n\n    c) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    d) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    e) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\f\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n                            NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\f\n           How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Lesser General Public\n    License as published by the Free Software Foundation; either\n    version 2.1 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!"
  },
  {
    "path": "licenses/Inno.txt",
    "content": "Inno Setup License\n==================\n\nExcept where otherwise noted, all of the documentation and software included\nin the Inno Setup package is copyrighted by Jordan Russell.\n\nCopyright (C) 1997-2013 Jordan Russell. All rights reserved.\nPortions Copyright (C) 2000-2013 Martijn Laan. All rights reserved.\n\nThis software is provided \"as-is,\" without any express or implied warranty.\nIn no event shall the author be held liable for any damages arising from the\nuse of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter and redistribute it,\nprovided that the following conditions are met:\n\n1. All redistributions of source code files must retain all copyright\n   notices that are currently in place, and this list of conditions without\n   modification.\n\n2. All redistributions in binary form must retain all occurrences of the\n   above copyright notice and web site addresses that are currently in\n   place (for example, in the About boxes).\n\n3. The origin of this software must not be misrepresented; you must not\n   claim that you wrote the original software. If you use this software to\n   distribute a product, an acknowledgment in the product documentation\n   would be appreciated but is not required.\n\n4. Modified versions in source or binary form must be plainly marked as\n   such, and must not be misrepresented as being the original software.\n\n\nJordan Russell\njr-2010 AT jrsoftware.org\nhttp://www.jrsoftware.org/"
  },
  {
    "path": "licenses/MUI.Extended.Toolkit.txt",
    "content": "MIT License\n\nCopyright (c) 2016 Sam Oates\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."
  },
  {
    "path": "licenses/MUI.txt",
    "content": "Microsoft Public License (Ms-PL)\n\nThis license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.\n\n1. Definitions\n\nThe terms \"reproduce,\" \"reproduction,\" \"derivative works,\" and \"distribution\" have the same meaning here as under U.S. copyright law.\n\nA \"contribution\" is the original software, or any additions or changes to the software.\n\nA \"contributor\" is any person that distributes its contribution under this license.\n\n\"Licensed patents\" are a contributor's patent claims that read directly on its contribution.\n\n2. Grant of Rights\n\n(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.\n\n(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.\n\n3. Conditions and Limitations\n\n(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.\n\n(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.\n\n(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.\n\n(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.\n\n(E) The software is licensed \"as-is.\" You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement."
  },
  {
    "path": "licenses/Media Foundation .NET.txt",
    "content": "                  GNU LIBRARY GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1991 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the library GPL.  It is\n numbered 2 because it goes with version 2 of the ordinary GPL.]\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Library General Public License, applies to some\nspecially designated Free Software Foundation software, and to any\nother libraries whose authors decide to use it.  You can use it for\nyour libraries, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if\nyou distribute copies of the library, or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link a program with the library, you must provide\ncomplete object files to the recipients so that they can relink them\nwith the library, after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  Our method of protecting your rights has two steps: (1) copyright\nthe library, and (2) offer you this license which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  Also, for each distributor's protection, we want to make certain\nthat everyone understands that there is no warranty for this free\nlibrary.  If the library is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original\nversion, so that any problems introduced by others will not reflect on\nthe original authors' reputations.\n\f\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that companies distributing free\nsoftware will individually obtain patent licenses, thus in effect\ntransforming the program into proprietary software.  To prevent this,\nwe have made it clear that any patent must be licensed for everyone's\nfree use or not licensed at all.\n\n  Most GNU software, including some libraries, is covered by the ordinary\nGNU General Public License, which was designed for utility programs.  This\nlicense, the GNU Library General Public License, applies to certain\ndesignated libraries.  This license is quite different from the ordinary\none; be sure to read it in full, and don't assume that anything in it is\nthe same as in the ordinary license.\n\n  The reason we have a separate public license for some libraries is that\nthey blur the distinction we usually make between modifying or adding to a\nprogram and simply using it.  Linking a program with a library, without\nchanging the library, is in some sense simply using the library, and is\nanalogous to running a utility program or application program.  However, in\na textual and legal sense, the linked executable is a combined work, a\nderivative of the original library, and the ordinary General Public License\ntreats it as such.\n\n  Because of this blurred distinction, using the ordinary General\nPublic License for libraries did not effectively promote software\nsharing, because most developers did not use the libraries.  We\nconcluded that weaker conditions might promote sharing better.\n\n  However, unrestricted linking of non-free programs would deprive the\nusers of those programs of all benefit from the free status of the\nlibraries themselves.  This Library General Public License is intended to\npermit developers of non-free programs to use free libraries, while\npreserving your freedom as a user of such programs to change the free\nlibraries that are incorporated in them.  (We have not seen how to achieve\nthis as regards changes in header files, but we have achieved it as regards\nchanges in the actual functions of the Library.)  The hope is that this\nwill lead to faster development of free libraries.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, while the latter only\nworks together with the library.\n\n  Note that it is possible for a library to be covered by the ordinary\nGeneral Public License rather than by this special one.\n\f\n                  GNU LIBRARY GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library which\ncontains a notice placed by the copyright holder or other authorized\nparty saying it may be distributed under the terms of this Library\nGeneral Public License (also called \"this License\").  Each licensee is\naddressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n  \n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\f\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n  6. As an exception to the Sections above, you may also compile or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    c) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    d) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe source code distributed need not include anything that is normally\ndistributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\f\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Library General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n                            NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\f\n           How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Library General Public\n    License as published by the Free Software Foundation; either\n    version 2 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Library General Public License for more details.\n\n    You should have received a copy of the GNU Library General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!"
  },
  {
    "path": "licenses/MouseKeyHook.txt",
    "content": "Copyright (c) 2004-2015, George Mamaladze All rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\n* Neither the name of asssdwd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "licenses/NAudio.txt",
    "content": "Microsoft Public License (Ms-PL)\n\nThis license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.\n\n1. Definitions\n\nThe terms \"reproduce,\" \"reproduction,\" \"derivative works,\" and \"distribution\" have the same meaning here as under U.S. copyright law.\n\nA \"contribution\" is the original software, or any additions or changes to the software.\n\nA \"contributor\" is any person that distributes its contribution under this license.\n\n\"Licensed patents\" are a contributor's patent claims that read directly on its contribution.\n\n2. Grant of Rights\n\n(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.\n\n(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.\n\n3. Conditions and Limitations\n\n(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.\n\n(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.\n\n(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.\n\n(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.\n\n(E) The software is licensed \"as-is.\" You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. "
  },
  {
    "path": "licenses/Newtonsoft.Json.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2007 James Newton-King\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "licenses/Ooki.Dialogs.txt",
    "content": "License agreement for Ookii.Dialogs.\n\nCopyright  Sven Groot (Ookii.org) 2009\nAll rights reserved.\n\n\nRedistribution and use in source and binary forms, with or without \nmodification, are permitted provided that the following conditions are met:\n\n1) Redistributions of source code must retain the above copyright notice, \n   this list of conditions and the following disclaimer. \n2) Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution. \n3) Neither the name of the ORGANIZATION nor the names of its contributors\n   may be used to endorse or promote products derived from this software\n   without specific prior written permission. \n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\nTHE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "licenses/ReactiveProperty.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018 neuecc, xin9le, okazuki\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\nall copies 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\nTHE SOFTWARE."
  },
  {
    "path": "licenses/ScreenToGif.txt",
    "content": "Captura.Webcam is adapted from ScreenToGif\n\n# Microsoft Public License (Ms-PL)\n\nThis license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.\n\n## 1. Definitions\n\nThe terms \"reproduce,\" \"reproduction,\" \"derivative works,\" and \"distribution\" have the same meaning here as under U.S. copyright law.\n\nA \"contribution\" is the original software, or any additions or changes to the software.\n\nA \"contributor\" is any person that distributes its contribution under this license.\n\n\"Licensed patents\" are a contributor's patent claims that read directly on its contribution.\n\n## 2. Grant of Rights\n\n(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.\n\n(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.\n\n## 3. Conditions and Limitations\n\n(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.\n\n(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.\n\n(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.\n\n(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.\n\n(E) The software is licensed \"as-is.\" You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement."
  },
  {
    "path": "licenses/SharpAvi.txt",
    "content": "The MIT License\n\nCopyright (c) 2013-2014 Vasili Maslov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "licenses/SharpDX.txt",
    "content": "Copyright (c) 2010-2014 SharpDX - Alexandre Mutel\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\nall copies 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\nTHE SOFTWARE."
  },
  {
    "path": "licenses/System.Reactive.txt",
    "content": "Copyright (c) .NET Foundation and Contributors\nAll Rights Reserved\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you\nmay not use this file except in compliance with the License. You may\nobtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\nimplied. See the License for the specific language governing permissions\nand limitations under the License."
  },
  {
    "path": "licenses/WPFNotifyIcon.txt",
    "content": "Code Project Open License (CPOL)\n\nhttps://www.codeproject.com/info/cpol10.aspx"
  },
  {
    "path": "licenses/WpfToolkit.txt",
    "content": "# Microsoft Public License (Ms-PL)\n\nThis license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.\n\n## 1. Definitions\n\nThe terms \"reproduce,\" \"reproduction,\" \"derivative works,\" and \"distribution\" have the same meaning here as under U.S. copyright law.\n\nA \"contribution\" is the original software, or any additions or changes to the software.\n\nA \"contributor\" is any person that distributes its contribution under this license.\n\n\"Licensed patents\" are a contributor's patent claims that read directly on its contribution.\n\n## 2. Grant of Rights\n\n(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.\n\n(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.\n\n## 3. Conditions and Limitations\n\n(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.\n\n(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.\n\n(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.\n\n(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.\n\n(E) The software is licensed \"as-is.\" You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement."
  },
  {
    "path": "scripts/apikeys.cake",
    "content": "#l \"constants.cake\"\n#l \"backup.cake\"\nusing System.Text.RegularExpressions;\n\nIEnumerable<string> GetVariables(string ApiKeysContent)\n{\n    var match = Regex.Match(ApiKeysContent, \"Get\\\\(\\\"(.*)\\\"\\\\)\");\n\n    while (match.Success)\n    {\n        yield return match.Groups[1].ToString();\n\n        match = match.NextMatch();\n    }\n}\n\nvoid EmbedApiKeys()\n{\n    var apiKeysPath = sourceFolder + File(\"Captura.Core/ApiKeys.cs\");\n\n    Information(\"Embedding Api Keys from Environment Variables ...\");\n\n    CreateBackup(apiKeysPath, tempFolder + File(\"ApiKeys.cs\"));\n\n    var content = FileRead(apiKeysPath);\n\n    foreach (var variable in GetVariables(content))\n    {\n        if (HasEnvironmentVariable(variable))\n        {\n            content = content.Replace($\"Get(\\\"{variable}\\\")\", $\"\\\"{EnvironmentVariable(variable)}\\\"\");\n        }\n    }\n\n    FileWrite(apiKeysPath, content);\n}"
  },
  {
    "path": "scripts/backup.cake",
    "content": "readonly var Backups = new List<Backup>();\n\nclass Backup\n{\n    public Backup(string OriginalPath, string BackupPath)\n    {\n        this.OriginalPath = OriginalPath;\n        this.BackupPath = BackupPath;\n    }\n\n    public string OriginalPath { get; }\n\n    public string BackupPath { get; }\n}\n\nvoid CreateBackup(string OriginalPath, string BackupPath)\n{\n    var backup = new Backup(OriginalPath, BackupPath);\n    CopyFile(OriginalPath, BackupPath);\n    Backups.Add(backup);\n}\n\nvoid RestoreBackups()\n{\n    Backups.ForEach(M =>\n    {\n        DeleteFile(M.OriginalPath);\n        MoveFile(M.BackupPath, M.OriginalPath);\n    });\n}\n\nstring FileRead(string FileName) => System.IO.File.ReadAllText(FileName);\n\nvoid FileWrite(string FileName, string Content) => System.IO.File.WriteAllText(FileName, Content);"
  },
  {
    "path": "scripts/choco.cake",
    "content": "#l \"constants.cake\"\n#l \"backup.cake\"\n#l \"version.cake\"\n\nreadonly var chocoVersion = tag?.Substring(1) ?? \"\";\n\nreadonly var ChocoPkgPath = tempFolder + File($\"captura.{chocoVersion}.nupkg\");\n\nvoid PackChoco()\n{\n    var checksum = CalculateFileHash(PortablePath).ToHex();\n\n    var chocoInstallScript = chocoFolder + File(\"tools/chocolateyinstall.ps1\");\n\n    var originalContent = FileRead(chocoInstallScript);\n\n    var newContent = $\"$tag = '{tag}'; $checksum = '{checksum}'; {originalContent}\";\n\n    CreateBackup(chocoInstallScript, tempFolder + File(\"cinst.ps1\"));\n\n    FileWrite(chocoInstallScript, newContent);\n\n    ChocolateyPack(chocoFolder + File(\"captura.nuspec\"), new ChocolateyPackSettings\n    {\n        Version = chocoVersion,\n        ArgumentCustomization = Args => Args.Append($\"--outputdirectory {tempFolder}\")\n    });\n}"
  },
  {
    "path": "scripts/constants.cake",
    "content": "readonly var sourceFolder = Directory(\"src\");\nreadonly var tempFolder = Directory(\"temp\");\nreadonly var distFolder = Directory(\"dist\");\nreadonly var licensesFolder = Directory(\"licenses\");\nreadonly var chocoFolder = Directory(\"choco\");\n\nreadonly var slnPath = sourceFolder + File(\"Captura.sln\");\n\nreadonly var PortablePath = tempFolder + File(\"Captura-Portable.zip\");\nreadonly var SetupPath = tempFolder + File(\"Captura-Setup.exe\");\n\nconst string Release = \"Release\";"
  },
  {
    "path": "scripts/version.cake",
    "content": "#l \"constants.cake\"\n#l \"backup.cake\"\nusing static System.Text.RegularExpressions.Regex;\n\n// version parameter is already used by cake.exe\nvar tag = Argument<string>(\"build_version\", \"v0.0.0\");\nvar version = tag;\n\nvoid UpdateVersion(string AssemblyInfoPath)\n{\n    var content = FileRead(AssemblyInfoPath);\n\n    var start = content.IndexOf(\"AssemblyVersion\");\n    var end = content.IndexOf(\")\", start);\n\n    var replace = content.Replace(content.Substring(start, end - start + 1), $\"AssemblyVersion(\\\"{version}\\\")\");\n\n    FileWrite(AssemblyInfoPath, replace);\n}\n\nvoid HandleVersion()\n{\n    const string StableVersionRegex = @\"^v\\d+\\.\\d+\\.\\d+$\";\n    const string PrereleaseVersionRegex = @\"^v\\d+\\.\\d+\\.\\d+-[^\\s]+$\";\n\n    // Stable Release or CI build\n    if (IsMatch(version, StableVersionRegex))\n    {\n        version = version.Substring(1);\n    }\n    // Prerelease\n    else if (IsMatch(version, PrereleaseVersionRegex))\n    {\n        version = version.Split('-')[0].Substring(1);\n    }\n    else throw new ArgumentException(\"Invalid Version Format\", \"build_version\");\n\n    var assemblyInfoFile = File(\"Properties/AssemblyInfo.cs\");\n    var uiAssemblyInfo = sourceFolder + Directory(\"Captura\") + assemblyInfoFile;\n    var consoleAssemblyInfo = sourceFolder + Directory(\"Captura.Console\") + assemblyInfoFile;\n\n    // Update AssemblyInfo files\n    CreateBackup(uiAssemblyInfo, tempFolder + File(\"AssemblyInfo.cs\"));\n    CreateBackup(consoleAssemblyInfo, tempFolder + File(\"console.cs\"));\n\n    UpdateVersion(uiAssemblyInfo);\n    UpdateVersion(consoleAssemblyInfo);\n}"
  },
  {
    "path": "src/Captura/App.xaml",
    "content": "﻿<Application x:Class=\"Captura.App\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:captura=\"clr-namespace:Captura\"\n             xmlns:loc=\"clr-namespace:Captura.Loc;assembly=Captura.Loc\"\n             ShutdownMode=\"OnMainWindowClose\"\n             StartupUri=\"Windows/MainWindow.xaml\"\n             Startup=\"Application_Startup\"\n             DispatcherUnhandledException=\"App_OnDispatcherUnhandledException\">\n    <Application.Resources>\n        <ResourceDictionary>\n            <ResourceDictionary.MergedDictionaries>\n                <ResourceDictionary Source=\"/FirstFloor.ModernUI;component/Assets/ModernUI.xaml\" />\n                <ResourceDictionary Source=\"/FirstFloor.ModernUI;component/Assets/ModernUI.Light.xaml\"/>\n                <ResourceDictionary Source=\"/ModernUI.Xceed.Toolkit;component/Assets/ModernUI.Xceed.Toolkit.xaml\" />\n                <ResourceDictionary Source=\"Presentation/Themes/ModernButton.xaml\" />\n                <ResourceDictionary Source=\"Presentation/Themes/ModernToggleButton.xaml\" />\n                <ResourceDictionary Source=\"Presentation/Themes/Generic.xaml\"/>\n                <ResourceDictionary Source=\"Presentation/Themes/RoundSlider.xaml\"/>\n                <ResourceDictionary Source=\"Presentation/Themes/VirtualizingItemsControl.xaml\"/>\n                <ResourceDictionary Source=\"ValueConverters/ValueConverters.xaml\"/>\n                <ResourceDictionary Source=\"Presentation/Themes/RegionPickerMagnifier.xaml\"/>\n                <ResourceDictionary Source=\"Presentation/Themes/Expander.xaml\"/>\n                <ResourceDictionary Source=\"Presentation/Themes/ModernTogglePill.xaml\"/>\n            </ResourceDictionary.MergedDictionaries>\n            \n            <x:Static x:Key=\"Loc\"\n                      Member=\"loc:LanguageManager.Instance\"/>\n\n            <captura:ServiceLocator x:Key=\"ServiceLocator\"/>\n\n            <DrawingImage x:Key=\"RecordStopImageSource\">\n                <DrawingImage.Drawing>\n                    <GeometryDrawing Geometry=\"{Binding RecordingViewModel.RecorderState.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource StateToRecordButtonGeometryConverter}}\"\n                                     Brush=\"#b71c1c\"/>\n                </DrawingImage.Drawing>\n            </DrawingImage>\n            <DrawingImage x:Key=\"ScreenShotImageSource\">\n                <DrawingImage.Drawing>\n                    <GeometryDrawing Geometry=\"{Binding Icons.Camera, Source={StaticResource ServiceLocator}}\"\n                                     Brush=\"{DynamicResource ItemText}\"/>\n                </DrawingImage.Drawing>\n            </DrawingImage>\n\n            <Style x:Key=\"CountdownLabel\" TargetType=\"Label\" BasedOn=\"{StaticResource {x:Type Label}}\">\n                <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n                <Setter Property=\"RenderTransformOrigin\" Value=\"0.5,0.5\"/>\n                <Setter Property=\"RenderTransform\">\n                    <Setter.Value>\n                        <ScaleTransform ScaleX=\"1\" ScaleY=\"1\"/>\n                    </Setter.Value>\n                </Setter>\n                <Style.Triggers>\n                    <Trigger Property=\"Visibility\" Value=\"Visible\">\n                        <Trigger.EnterActions>\n                            <BeginStoryboard Name=\"BeginCountdownAnim\">\n                                <Storyboard>\n                                    <DoubleAnimation Storyboard.TargetProperty=\"RenderTransform.ScaleX\"\n                                                     To=\"2\"\n                                                     Duration=\"00:00:00.5\"\n                                                     AutoReverse=\"True\"\n                                                     RepeatBehavior=\"Forever\"/>\n                                    <DoubleAnimation Storyboard.TargetProperty=\"RenderTransform.ScaleY\"\n                                                     To=\"2\"\n                                                     Duration=\"00:00:00.5\"\n                                                     AutoReverse=\"True\"\n                                                     RepeatBehavior=\"Forever\"/>\n                                </Storyboard>\n                            </BeginStoryboard>\n                        </Trigger.EnterActions>\n                        <Trigger.ExitActions>\n                            <StopStoryboard BeginStoryboardName=\"BeginCountdownAnim\"/>\n                        </Trigger.ExitActions>\n                    </Trigger>\n                </Style.Triggers>\n            </Style>\n        </ResourceDictionary>\n    </Application.Resources>\n</Application>"
  },
  {
    "path": "src/Captura/App.xaml.cs",
    "content": "﻿using FirstFloor.ModernUI.Presentation;\nusing System;\nusing System.IO;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Threading;\nusing Captura.Loc;\nusing Captura.Models;\nusing Captura.MouseKeyHook;\nusing Captura.ViewModels;\nusing Captura.Views;\nusing CommandLine;\n\nnamespace Captura\n{\n    public partial class App\n    {\n        public App()\n        {\n            SingleInstanceManager.SingleInstanceCheck();\n\n            // Splash Screen should be created manually and after single-instance is checked\n            ShowSplashScreen();\n        }\n\n        public static CmdOptions CmdOptions { get; private set; }\n        \n        void App_OnDispatcherUnhandledException(object Sender, DispatcherUnhandledExceptionEventArgs Args)\n        {\n            var dir = Path.Combine(ServiceProvider.SettingsDir, \"Crashes\");\n\n            Directory.CreateDirectory(dir);\n\n            File.WriteAllText(Path.Combine(dir, $\"{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt\"), Args.Exception.ToString());\n\n            Args.Handled = true;\n\n            new ErrorWindow(Args.Exception, Args.Exception.Message).ShowDialog();\n        }\n\n        void ShowSplashScreen()\n        {\n            var splashScreen = new SplashScreen(\"Images/Logo.png\");\n            splashScreen.Show(true);\n        }\n\n        void Application_Startup(object Sender, StartupEventArgs Args)\n        {\n            AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainOnUnhandledException;\n\n            ServiceProvider.LoadModule(new CoreModule());\n            ServiceProvider.LoadModule(new ViewCoreModule());\n\n            Parser.Default.ParseArguments<CmdOptions>(Args.Args)\n                .WithParsed(M => CmdOptions = M);\n\n            if (CmdOptions.Settings != null)\n            {\n                ServiceProvider.SettingsDir = CmdOptions.Settings;\n            }\n\n            var settings = ServiceProvider.Get<Settings>();\n\n            InitTheme(settings);\n\n            BindLanguageSetting(settings);\n\n            BindKeymapSetting(settings);\n        }\n\n        void OnCurrentDomainOnUnhandledException(object S, UnhandledExceptionEventArgs E)\n        {\n            var dir = Path.Combine(ServiceProvider.SettingsDir, \"Crashes\");\n\n            Directory.CreateDirectory(dir);\n\n            File.WriteAllText(Path.Combine(dir, $\"{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt\"), E.ExceptionObject.ToString());\n\n            if (E.ExceptionObject is Exception e)\n            {\n                Current.Dispatcher.Invoke(() => new ErrorWindow(e, e.Message).ShowDialog());\n            }\n\n            Shutdown();\n        }\n\n        static void BindKeymapSetting(Settings Settings)\n        {\n            var keymap = ServiceProvider.Get<KeymapViewModel>();\n\n            if (!string.IsNullOrWhiteSpace(Settings.Keystrokes.KeymapName))\n            {\n                var matched = keymap.AvailableKeymaps.FirstOrDefault(M => M.Name == Settings.Keystrokes.KeymapName);\n\n                if (matched != null)\n                    keymap.SelectedKeymap = matched;\n            }\n\n            keymap.PropertyChanged += (S, E) => Settings.Keystrokes.KeymapName = keymap.SelectedKeymap.Name;\n        }\n\n        static void BindLanguageSetting(Settings Settings)\n        {\n            var loc = LanguageManager.Instance;\n\n            if (!string.IsNullOrWhiteSpace(Settings.UI.Language))\n            {\n                var matchedCulture = loc.AvailableCultures.FirstOrDefault(M => M.Name == Settings.UI.Language);\n\n                if (matchedCulture != null)\n                    loc.CurrentCulture = matchedCulture;\n            }\n\n            loc.LanguageChanged += L => Settings.UI.Language = L.Name;\n        }\n\n        static void InitTheme(Settings Settings)\n        {\n            if (!CmdOptions.Reset)\n            {\n                Settings.Load();\n            }\n\n            if (Settings.UI.DarkTheme)\n            {\n                AppearanceManager.Current.ThemeSource = AppearanceManager.DarkThemeSource;\n            }\n\n            var accent = Settings.UI.AccentColor;\n\n            if (!string.IsNullOrEmpty(accent))\n            {\n                AppearanceManager.Current.AccentColor = WpfExtensions.ParseColor(accent);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Captura.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.WindowsDesktop\">\n  <PropertyGroup>\n    <OutputType>WinExe</OutputType>\n    <RootNamespace>Captura</RootNamespace>\n    <AssemblyName>captura</AssemblyName>\n    <TargetFramework>net472</TargetFramework>\n    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\n    <UseWPF>true</UseWPF>\n    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\n    <ApplicationIcon>Images\\Captura.ico</ApplicationIcon>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <ItemGroup>\n    <Resource Include=\"Images\\Logo.png\" />\n    <Resource Include=\"Images\\record.ico\" />\n    <Resource Include=\"Images\\Captura.ico\" />\n    <Resource Include=\"Images\\pause.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Reference Include=\"System.Management\" />\n    <Reference Include=\"WindowsFormsIntegration\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Core\\Captura.Core.csproj\" />\n    <ProjectReference Include=\"..\\Captura.FFmpeg\\Captura.FFmpeg.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Hotkeys\\Captura.Hotkeys.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Loc\\Captura.Loc.csproj\" />\n    <ProjectReference Include=\"..\\Captura.MouseKeyHook\\Captura.MouseKeyHook.csproj\" />\n    <ProjectReference Include=\"..\\Captura.SharpAvi\\Captura.SharpAvi.csproj\" />\n    <ProjectReference Include=\"..\\Captura.ViewCore\\Captura.ViewCore.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Windows\\Captura.Windows.csproj\" />\n    <ProjectReference Include=\"..\\Captura.YouTube\\Captura.YouTube.csproj\" />\n    <ProjectReference Include=\"..\\Screna\\Screna.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"CommandLineParser\" Version=\"2.2.1\" />\n    <PackageReference Include=\"Extended.Wpf.Toolkit\" Version=\"3.0.0\" />\n    <PackageReference Include=\"Hardcodet.NotifyIcon.Wpf\" Version=\"1.0.8\" />\n    <PackageReference Include=\"ModernUI.WPF\" Version=\"1.0.9\" />\n    <PackageReference Include=\"SamOatesGames.ModernUI.Xceed.Toolkit\" Version=\"1.0.0\" />\n  </ItemGroup>\n  <Target Name=\"Delete unused libs\" AfterTargets=\"Build\">\n    <ItemGroup>\n      <AvalonDockLibs Include=\"$(OutputPath)Xceed.Wpf.AvalonDock*.dll\" />\n    </ItemGroup>\n    <Delete Files=\"@(AvalonDockLibs)\" />\n    <Delete Files=\"$(OutputPath)Xceed.Wpf.DataGrid.dll\" />\n  </Target>\n  <Import Project=\"../PostBuild.targets\" />\n</Project>"
  },
  {
    "path": "src/Captura/Controls/CollapsedBar.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.CollapsedBar\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n             xmlns:captura=\"clr-namespace:Captura\"\n             DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\"\n             mc:Ignorable=\"d\">\n    <Grid>\n        <Grid.Resources>\n            <Style TargetType=\"Path\" x:Key=\"VideoSourceIcon\" BasedOn=\"{StaticResource {x:Type Path}}\">\n                <Setter Property=\"Width\" Value=\"12\"/>\n                <Setter Property=\"Height\" Value=\"12\"/>\n                <Setter Property=\"Margin\" Value=\"0\"/>\n                <Setter Property=\"Stretch\" Value=\"Uniform\"/>\n                <Setter Property=\"HorizontalAlignment\" Value=\"Center\"/>\n                <Setter Property=\"VerticalAlignment\" Value=\"Center\"/>\n                <Setter Property=\"Fill\" Value=\"{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=ContentControl}}\"/>\n            </Style>\n            <Style TargetType=\"captura:ModernToggleButton\" BasedOn=\"{StaticResource {x:Type captura:ModernToggleButton}}\">\n                <Setter Property=\"LayoutTransform\">\n                    <Setter.Value>\n                        <ScaleTransform ScaleX=\"0.85\" ScaleY=\"0.85\"/>\n                    </Setter.Value>\n                </Setter>\n            </Style>\n        </Grid.Resources>\n        <Border CornerRadius=\"15,15,25,25\"\n                BorderThickness=\"0\"\n                Margin=\"0,2,0,0\"\n                HorizontalAlignment=\"Right\"\n                VerticalAlignment=\"Bottom\"\n                Width=\"70\"\n                Height=\"33\"\n                Background=\"{DynamicResource ButtonBackgroundHover}\"/>\n        <DockPanel>\n            <captura:ModernButton ToolTip=\"{Binding Configure, Source={StaticResource Loc}, Mode=OneWay}\"\n                                  Click=\"OpenSettings\"\n                                  Foreground=\"{DynamicResource Accent}\"\n                                  IconData=\"{Binding Icons.Settings, Source={StaticResource ServiceLocator}}\"\n                                  DockPanel.Dock=\"Right\"\n                                  RenderTransformOrigin=\"0.5,0.5\">\n                <captura:ModernButton.RenderTransform>\n                    <RotateTransform/>\n                </captura:ModernButton.RenderTransform>\n                <captura:ModernButton.Triggers>\n                    <EventTrigger RoutedEvent=\"captura:ModernButton.MouseEnter\">\n                        <EventTrigger.Actions>\n                            <BeginStoryboard>\n                                <Storyboard>\n                                    <DoubleAnimation Storyboard.TargetProperty=\"RenderTransform.Angle\"\n                                                     To=\"110\"\n                                                     Duration=\"0:0:0.15\"/>\n                                </Storyboard>\n                            </BeginStoryboard>\n                        </EventTrigger.Actions>\n                    </EventTrigger>\n                    <EventTrigger RoutedEvent=\"captura:ModernButton.MouseLeave\">\n                        <EventTrigger.Actions>\n                            <BeginStoryboard>\n                                <Storyboard>\n                                    <DoubleAnimation Storyboard.TargetProperty=\"RenderTransform.Angle\"\n                                                     To=\"0\"\n                                                     Duration=\"0:0:0.15\"/>\n                                </Storyboard>\n                            </BeginStoryboard>\n                        </EventTrigger.Actions>\n                    </EventTrigger>\n                </captura:ModernButton.Triggers>\n            </captura:ModernButton>\n\n            <captura:ModernButton ToolTip=\"{Binding OpenOutFolder, Source={StaticResource Loc}, Mode=OneWay}\"\n                                  Command=\"{Binding OpenOutputFolderCommand}\"\n                                  IconData=\"{Binding Icons.Folder, Source={StaticResource ServiceLocator}}\"\n                                  DockPanel.Dock=\"Right\"/>\n\n            <StackPanel Orientation=\"Horizontal\">\n                <captura:ModernToggleButton ToolTip=\"Microphone\"\n                                            IconData=\"{Binding Icons.Mic, Source={StaticResource ServiceLocator}}\"\n                                            IsChecked=\"{Binding Settings.Audio.RecordMicrophone, Mode=TwoWay}\"/>\n\n                <captura:ModernToggleButton ToolTip=\"Speaker\"\n                                            IconData=\"{Binding Icons.Speaker, Source={StaticResource ServiceLocator}}\"\n                                            IsChecked=\"{Binding Settings.Audio.RecordSpeaker, Mode=TwoWay}\"/>\n            </StackPanel>\n\n            <captura:VideoSourceKindList/>\n        </DockPanel>\n    </Grid>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/CollapsedBar.xaml.cs",
    "content": "﻿using System.Windows;\n\nnamespace Captura\n{\n    public partial class CollapsedBar\n    {\n        public CollapsedBar()\n        {\n            InitializeComponent();\n        }\n\n        void OpenSettings(object Sender, RoutedEventArgs E)\n        {\n            SettingsWindow.ShowInstance();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/FontSelector.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.FontSelector\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n             mc:Ignorable=\"d\" \n             d:DesignHeight=\"30\" d:DesignWidth=\"200\"\n             Name=\"This\">\n    <ComboBox ItemsSource=\"{Binding Source={x:Static Fonts.SystemFontFamilies}}\"\n              SelectedValue=\"{Binding SelectedFont, ElementName=This, Mode=TwoWay}\"\n              SelectedValuePath=\"Source\"\n              ToolTip=\"{Binding SelectedFont, ElementName=This}\"/>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/FontSelector.xaml.cs",
    "content": "﻿using System.Windows;\n\nnamespace Captura\n{\n    public partial class FontSelector\n    {\n        public FontSelector()\n        {\n            InitializeComponent();\n        }\n\n        public static readonly DependencyProperty SelectedFontProperty = DependencyProperty.Register(\n            nameof(SelectedFont),\n            typeof(string),\n            typeof(FontSelector),\n            new FrameworkPropertyMetadata(\"Arial\"));\n\n        public string SelectedFont\n        {\n            get => (string) GetValue(SelectedFontProperty);\n            set => SetValue(SelectedFontProperty, value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/HotkeySelector.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Forms;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing Captura.Hotkeys;\nusing Button = System.Windows.Controls.Button;\nusing KeyEventArgs = System.Windows.Input.KeyEventArgs;\n\nnamespace Captura\n{\n    public class HotkeySelector : Button\n    {\n        bool _editing;\n\n        static readonly SolidColorBrush RedBrush = new SolidColorBrush(WpfExtensions.ParseColor(\"#ef5350\"));\n        static readonly SolidColorBrush GreenBrush = new SolidColorBrush(WpfExtensions.ParseColor(\"#43a047\"));\n\n        static readonly SolidColorBrush WhiteBrush = new SolidColorBrush(Colors.White);\n\n        public static readonly DependencyProperty HotkeyModelProperty = DependencyProperty.Register(nameof(HotkeyModel),\n            typeof(Hotkey),\n            typeof(HotkeySelector),\n            new UIPropertyMetadata(HotkeyModelChangedCallback));\n\n        static void HotkeyModelChangedCallback(DependencyObject Sender, DependencyPropertyChangedEventArgs Args)\n        {\n            if (Sender is HotkeySelector selector && Args.NewValue is Hotkey hotkey)\n            {\n                selector.TextColor();\n\n                hotkey.PropertyChanged += (S, E) =>\n                {\n                    if (E.PropertyName == nameof(Hotkey.IsActive))\n                        selector.TextColor();\n                };\n\n                selector.Content = hotkey.ToString();\n            }\n        }\n\n        public Hotkey HotkeyModel\n        {\n            get => (Hotkey) GetValue(HotkeyModelProperty);\n            set => SetValue(HotkeyModelProperty, value);\n        }\n\n        void HotkeyEdited(Key NewKey, Modifiers NewModifiers)\n        {\n            HotkeyEdited((Keys) KeyInterop.VirtualKeyFromKey(NewKey), NewModifiers);\n        }\n\n        void TextColor()\n        {\n            if (HotkeyModel.IsActive)\n            {\n                Background = HotkeyModel.IsRegistered ? GreenBrush : RedBrush;\n\n                Foreground = WhiteBrush;\n            }\n            else\n            {\n                ClearValue(BackgroundProperty);\n\n                ClearValue(ForegroundProperty);\n            }\n        }\n\n        void HotkeyEdited(Keys NewKey, Modifiers NewModifiers)\n        {\n            HotkeyModel.Change(NewKey, NewModifiers);\n\n            // Red Text on Error\n            TextColor();\n\n            Content = HotkeyModel.ToString();\n\n            _editing = false;\n        }\n        \n        protected override void OnClick()\n        {\n            base.OnClick();\n\n            _editing = !_editing;\n\n            Content = _editing ? \"Press new Hotkey...\" : HotkeyModel.ToString();\n        }\n\n        protected override void OnLostFocus(RoutedEventArgs E)\n        {\n            base.OnLostFocus(E);\n\n            CancelEditing();\n        }\n\n        void CancelEditing()\n        {\n            if (!_editing)\n                return;\n\n            _editing = false;\n            Content = HotkeyModel.ToString();\n        }\n\n        static bool IsValid(KeyEventArgs E)\n        {\n            return E.Key != Key.None // Some key must pe pressed\n                && !E.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Windows) // Windows Key is reserved by OS\n                && E.Key != Key.LeftCtrl && E.Key != Key.RightCtrl // Modifier Keys alone are not supported\n                && E.Key != Key.LeftAlt && E.Key != Key.RightAlt\n                && E.Key != Key.LeftShift && E.Key != Key.RightShift;\n        }\n\n        protected override void OnPreviewKeyDown(KeyEventArgs E)\n        {\n            // Ignore Repeats\n            if (E.IsRepeat)\n            {\n                E.Handled = true;\n                return;\n            }\n\n            if (_editing)\n            {\n                // Suppress event propagation\n                E.Handled = true;\n\n                switch (E.Key)\n                {\n                    case Key.Escape:\n                        CancelEditing();\n                        break;\n\n                    case Key.System:\n                        if (E.SystemKey == Key.LeftAlt || E.SystemKey == Key.RightAlt)\n                            Content = \"Alt + ...\";\n                        else HotkeyEdited(E.SystemKey, Modifiers.Alt);\n                        break;\n\n                    default:\n                        if (IsValid(E))\n                            HotkeyEdited(E.Key, (Modifiers)E.KeyboardDevice.Modifiers);\n\n                        else\n                        {\n                            var modifiers = E.KeyboardDevice.Modifiers;\n\n                            Content = \"\";\n\n                            if (modifiers.HasFlag(ModifierKeys.Control))\n                                Content += \"Ctrl + \";\n\n                            if (modifiers.HasFlag(ModifierKeys.Alt))\n                                Content += \"Alt + \";\n\n                            if (modifiers.HasFlag(ModifierKeys.Shift))\n                                Content += \"Shift + \";\n\n                            Content += \"...\";\n                        }\n                        break;\n                }\n            }\n\n            base.OnPreviewKeyDown(E);\n        }\n\n        protected override void OnPreviewKeyUp(KeyEventArgs E)\n        {\n            // Ignore Repeats\n            if (E.IsRepeat)\n                return;\n\n            if (_editing)\n            {\n                // Suppress event propagation\n                E.Handled = true;\n\n                // PrintScreen is not recognized in KeyDown\n                switch (E.Key)\n                {\n                    case Key.Snapshot:\n                        HotkeyEdited(Keys.PrintScreen, (Modifiers)E.KeyboardDevice.Modifiers);\n                        break;\n\n                    case Key.System when E.SystemKey == Key.Snapshot:\n                        HotkeyEdited(Keys.PrintScreen, Modifiers.Alt);\n                        break;\n                }\n            }\n\n            base.OnPreviewKeyUp(E);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Controls/ImageOverlaySettingsControl.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.ImageOverlaySettingsControl\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:local=\"clr-namespace:Captura\"\n             xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n             xmlns:video=\"clr-namespace:Captura.Video;assembly=Screna\"\n             mc:Ignorable=\"d\"\n             d:DataContext=\"{d:DesignInstance video:ImageOverlaySettings}\">\n    <StackPanel>\n        <local:PositionSettingsControl/>\n\n        <Grid Margin=\"0,15,0,5\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"*\"/>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"*\"/>\n            </Grid.ColumnDefinitions>\n\n            <CheckBox Content=\"{Binding Resize, Source={StaticResource Loc}, Mode=OneWay}\"\n                      IsChecked=\"{Binding Resize, Mode=TwoWay}\"\n                      Margin=\"0,0,5,0\"/>\n\n            <xctk:IntegerUpDown Value=\"{Binding ResizeWidth, Mode=TwoWay}\"\n                                Grid.Column=\"1\"\n                                Minimum=\"1\"\n                                IsEnabled=\"{Binding Resize}\"/>\n\n            <Label Content=\"x\"\n                   Grid.Column=\"2\"\n                   Margin=\"5,0\"/>\n\n            <xctk:IntegerUpDown Value=\"{Binding ResizeHeight, Mode=TwoWay}\"\n                                Grid.Column=\"3\"\n                                Minimum=\"1\"\n                                IsEnabled=\"{Binding Resize}\"/>\n        </Grid>\n\n        <Grid Margin=\"0,15,0,5\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"*\"/>\n            </Grid.ColumnDefinitions>\n\n            <Path Data=\"{Binding Icons.Opacity, Source={StaticResource ServiceLocator}}\"\n                  Width=\"15\"\n                  Height=\"15\"\n                  Margin=\"0,0,10,0\"\n                  Stretch=\"Uniform\"\n                  HorizontalAlignment=\"Center\"\n                  VerticalAlignment=\"Center\"/>\n\n            <Label Content=\"{Binding Opacity, Source={StaticResource Loc}, Mode=OneWay}\"\n                   ContentStringFormat=\"{}{0}: \"\n                   Grid.Column=\"1\"\n                   Margin=\"0,3\"/>\n\n            <xctk:IntegerUpDown Value=\"{Binding Opacity, Mode=TwoWay}\"\n                                Grid.Column=\"2\"\n                                Minimum=\"1\"\n                                Maximum=\"100\"/>\n        </Grid>\n    </StackPanel>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/ImageOverlaySettingsControl.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class ImageOverlaySettingsControl\n    {\n        public ImageOverlaySettingsControl()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/LayerFrame.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.LayerFrame\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n             mc:Ignorable=\"d\" \n             d:DesignHeight=\"300\" d:DesignWidth=\"300\">\n    <Border Name=\"Border\"\n            Background=\"Brown\">\n        <Label Name=\"Label\"\n               HorizontalAlignment=\"Center\"/>\n    </Border>\n    <UserControl.Effect>\n        <DropShadowEffect ShadowDepth=\"1\"\n                          Opacity=\"0.5\"/>\n    </UserControl.Effect>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/LayerFrame.xaml.cs",
    "content": "﻿using System;\nusing System.Windows;\n\nnamespace Captura\n{\n    public partial class LayerFrame\n    {\n        public LayerFrame()\n        {\n            InitializeComponent();\n        }\n\n        public event Action<Rect> PositionUpdated;\n\n        public void RaisePositionChanged(Rect Rect)\n        {\n            PositionUpdated?.Invoke(Rect);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Controls/ModernButton.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Media;\n\nnamespace Captura\n{\n    public class ModernButton : Button\n    {\n        public static readonly DependencyProperty IconDataProperty = DependencyProperty.Register(nameof(IconData), typeof(Geometry), typeof(ModernButton));\n     \n        public ModernButton() { DefaultStyleKey = typeof(ModernButton); }\n        \n        public Geometry IconData\n        {\n            get => (Geometry)GetValue(IconDataProperty);\n            set => SetValue(IconDataProperty, value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/ModernPasswordBox.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.ModernPasswordBox\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n             xmlns:mui=\"http://firstfloorsoftware.com/ModernUI\"\n             mc:Ignorable=\"d\" \n             d:DesignHeight=\"20\"\n             d:DesignWidth=\"200\"\n             Name=\"This\">\n    <Grid>\n        <TextBox Text=\"{Binding Password, ElementName=This, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"\n                 Padding=\"2,1,15,1\"\n                 Visibility=\"{Binding PasswordVisible, ElementName=This, Converter={StaticResource BoolToVisibilityConverter}}\"/>\n        <PasswordBox Name=\"PswBox\"\n                     Padding=\"2,1,15,1\"\n                     Visibility=\"{Binding PasswordVisible, ElementName=This, Converter={StaticResource NegatingConverter}}\"/>\n        <mui:ModernButton EllipseStrokeThickness=\"0\"\n                          Click=\"ToggleVisibility\"\n                          Visibility=\"{Binding Password, ElementName=This, Converter={StaticResource NotNullConverter}}\"\n                          HorizontalAlignment=\"Right\">\n            <mui:ModernButton.Style>\n                <Style TargetType=\"mui:ModernButton\" BasedOn=\"{StaticResource {x:Type mui:ModernButton}}\">\n                    <Setter Property=\"IconData\" Value=\"{Binding Icons.Visibility, Source={StaticResource ServiceLocator}}\"/>\n\n                    <Style.Triggers>\n                        <DataTrigger Binding=\"{Binding PasswordVisible, ElementName=This}\" Value=\"True\">\n                            <Setter Property=\"IconData\" Value=\"{Binding Icons.VisibilityHide, Source={StaticResource ServiceLocator}}\"/>\n                        </DataTrigger>\n                    </Style.Triggers>\n                </Style>\n            </mui:ModernButton.Style>\n        </mui:ModernButton>\n    </Grid>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/ModernPasswordBox.xaml.cs",
    "content": "﻿using System.Windows;\n\nnamespace Captura\n{\n    public partial class ModernPasswordBox\n    {\n        public ModernPasswordBox()\n        {\n            InitializeComponent();\n\n            PswBox.PasswordChanged += (S, E) => Password = PswBox.Password;\n        }\n\n        public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register(\n            nameof(Password),\n            typeof(string),\n            typeof(ModernPasswordBox),\n            new UIPropertyMetadata((S, E) =>\n            {\n                if (S is ModernPasswordBox modernPswBox && E.NewValue is string psw)\n                {\n                    if (modernPswBox.PswBox.Password != psw)\n                        modernPswBox.PswBox.Password = psw;\n                }\n            }));\n\n        public string Password\n        {\n            get => (string) GetValue(PasswordProperty);\n            set => SetValue(PasswordProperty, value);\n        }\n\n        public static readonly DependencyProperty PasswordVisibleProperty = DependencyProperty.Register(\n            nameof(PasswordVisible),\n            typeof(bool),\n            typeof(ModernPasswordBox));\n\n        public bool PasswordVisible\n        {\n            get => (bool)GetValue(PasswordVisibleProperty);\n            set => SetValue(PasswordVisibleProperty, value);\n        }\n\n        void ToggleVisibility(object Sender, RoutedEventArgs E)\n        {\n            PasswordVisible = !PasswordVisible;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/ModernToggleButton.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Media;\n\nnamespace Captura\n{\n    public class ModernToggleButton : CheckBox\n    {\n        public static readonly DependencyProperty IconDataProperty = DependencyProperty.Register(nameof(IconData), typeof(Geometry), typeof(ModernToggleButton));\n        \n        public ModernToggleButton() { DefaultStyleKey = typeof(ModernToggleButton); }\n        \n        public Geometry IconData\n        {\n            get => (Geometry)GetValue(IconDataProperty);\n            set => SetValue(IconDataProperty, value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/NotificationBalloon.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.NotificationBalloon\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:local=\"clr-namespace:Captura\"\n             BorderThickness=\"0,1,0,0\"\n             Padding=\"5,0,0,0\"\n             BorderBrush=\"{DynamicResource Accent}\"\n             DataContext=\"{Binding Notification, RelativeSource={RelativeSource Self}}\">\n    <DockPanel>\n        <ProgressBar Value=\"{Binding Progress, Mode=OneWay}\"\n                     Height=\"5\"\n                     Margin=\"-5,0,0,0\"\n                     DockPanel.Dock=\"Bottom\"\n                     Visibility=\"{Binding Progress, Converter={StaticResource NotNullConverter}}\"/>\n        \n        <local:ModernButton ToolTip=\"{Binding Close, Source={StaticResource Loc}, Mode=OneWay}\"\n                            Click=\"CloseButton_Click\"\n                            Foreground=\"LightPink\"\n                            IconData=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"\n                            DockPanel.Dock=\"Right\"/>\n\n        <ItemsControl DockPanel.Dock=\"Right\"\n                      ItemsSource=\"{Binding Actions}\">\n            <ItemsControl.ItemTemplate>\n                <DataTemplate>\n                    <local:ModernButton ToolTip=\"{Binding Name}\"\n                                        Command=\"{Binding ClickCommand}\"\n                                        Foreground=\"{Binding Color, TargetNullValue=White}\"\n                                        IconData=\"{Binding Icon}\"\n                                        DockPanel.Dock=\"Right\"/>\n                </DataTemplate>\n            </ItemsControl.ItemTemplate>\n            <ItemsControl.ItemsPanel>\n                <ItemsPanelTemplate>\n                    <StackPanel Orientation=\"Horizontal\"/>\n                </ItemsPanelTemplate>\n            </ItemsControl.ItemsPanel>\n        </ItemsControl>\n\n        <Label DockPanel.Dock=\"Bottom\"\n               Visibility=\"{Binding SecondaryText, Converter={StaticResource NotNullConverter}}\"\n               MouseUp=\"TextBlock_MouseUp\"\n               Cursor=\"Hand\">\n            <TextBlock Text=\"{Binding SecondaryText}\"\n                       Padding=\"5,0,5,5\"\n                       Style=\"{StaticResource Small}\"/>\n        </Label>\n\n        <Label MouseUp=\"TextBlock_MouseUp\"\n               Cursor=\"Hand\">\n            <TextBlock Text=\"{Binding PrimaryText}\"\n                       VerticalAlignment=\"Center\"\n                       Padding=\"5\"/>\n        </Label>\n    </DockPanel>\n</UserControl>"
  },
  {
    "path": "src/Captura/Controls/NotificationBalloon.xaml.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Input;\nusing System;\n\nnamespace Captura\n{\n    public partial class NotificationBalloon : IRemoveRequester\n    {\n        public INotification Notification { get; }\n\n        public NotificationBalloon(INotification Notification)\n        {\n            this.Notification = Notification;\n\n            Notification.RemoveRequested += OnClose;\n\n            InitializeComponent();\n        }\n\n        void OnClose()\n        {\n            RemoveRequested?.Invoke();\n        }\n\n        public event Action RemoveRequested;\n\n        void CloseButton_Click(object Sender, RoutedEventArgs E) => OnClose();\n        \n        void TextBlock_MouseUp(object Sender, MouseButtonEventArgs E)\n        {\n            Notification.RaiseClick();\n\n            OnClose();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Controls/NotificationStack.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.NotificationStack\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:local=\"clr-namespace:Captura\"\n             Width=\"400\"\n             Margin=\"10,60\"\n             BorderThickness=\"1\"\n             BorderBrush=\"{DynamicResource Accent}\"\n             Background=\"{DynamicResource WindowBackground}\"\n             MouseMove=\"NotificationStack_OnMouseMove\">\n    <UserControl.Resources>\n        <ResourceDictionary>\n            <ResourceDictionary.MergedDictionaries>\n                <ResourceDictionary Source=\"/FirstFloor.ModernUI;component/Assets/ModernUI.Dark.xaml\"/>\n            </ResourceDictionary.MergedDictionaries>\n        </ResourceDictionary>\n    </UserControl.Resources>\n    <DockPanel>\n        <DockPanel DockPanel.Dock=\"Top\">\n            <local:ModernButton ToolTip=\"{Binding Close, Source={StaticResource Loc}, Mode=OneWay}\"\n                                Click=\"CloseButton_Click\"\n                                IconData=\"{Binding Icons.ClearNotifications, Source={StaticResource ServiceLocator}}\"\n                                DockPanel.Dock=\"Right\"/>\n\n            <Label>\n                <TextBlock Text=\"{Binding Notifications, Source={StaticResource Loc}, Mode=OneWay}\"\n                           VerticalAlignment=\"Center\"\n                           Style=\"{StaticResource Title}\"\n                           Padding=\"5\"/>\n            </Label>\n        </DockPanel>\n        \n        <ScrollViewer>\n            <ItemsControl Name=\"ItemsControl\"/>\n        </ScrollViewer>\n    </DockPanel>\n</UserControl>"
  },
  {
    "path": "src/Captura/Controls/NotificationStack.xaml.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Media;\nusing System.Windows.Media.Animation;\nusing System.Windows.Threading;\nusing MouseEventArgs = System.Windows.Input.MouseEventArgs;\n\nnamespace Captura\n{\n    public partial class NotificationStack\n    {\n        static readonly TimeSpan TimeoutToHide = TimeSpan.FromSeconds(5);\n        DateTime _lastMouseMoveTime;\n        readonly DispatcherTimer _timer;\n\n        public NotificationStack()\n        {\n            InitializeComponent();\n\n            _timer = new DispatcherTimer\n            {\n                Interval = TimeSpan.FromSeconds(1)\n            };\n\n            _timer.Tick += TimerOnTick;\n\n            _timer.Start();\n        }\n\n        void TimerOnTick(object Sender, EventArgs Args)\n        {\n            var now = DateTime.Now;\n            var elapsed = now - _lastMouseMoveTime;\n\n            var unfinished = ItemsControl.Items\n                .OfType<NotificationBalloon>()\n                .Any(M => !M.Notification.Finished);\n\n            if (unfinished)\n            {\n                _lastMouseMoveTime = now;\n            }\n\n            if (elapsed < TimeoutToHide)\n                return;\n\n            if (!unfinished)\n            {\n                OnClose();\n            }\n        }\n\n        public void Hide()\n        {\n            BeginAnimation(OpacityProperty, new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(100))));\n\n            if (_timer.IsEnabled)\n                _timer.Stop();\n        }\n\n        public void Show()\n        {\n            _lastMouseMoveTime = DateTime.Now;\n\n            BeginAnimation(OpacityProperty, new DoubleAnimation(1, new Duration(TimeSpan.FromMilliseconds(300))));\n\n            if (!_timer.IsEnabled)\n                _timer.Start();\n        }\n\n        void OnClose()\n        {\n            Hide();\n\n            var copy = ItemsControl.Items.OfType<FrameworkElement>().ToArray();\n\n            foreach (var frameworkElement in copy)\n            {\n                Remove(frameworkElement);\n            }\n        }\n\n        void CloseButton_Click(object Sender, RoutedEventArgs E) => OnClose();\n\n        /// <summary>\n        /// Slides out element while decreasing opacity, then decreases height, then removes.\n        /// </summary>\n        void Remove(FrameworkElement Element)\n        {\n            var transform = new TranslateTransform();\n            Element.RenderTransform = transform;\n\n            var translateAnim = new DoubleAnimation(500, new Duration(TimeSpan.FromMilliseconds(200)));\n            var opactityAnim = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(200)));\n\n            var heightAnim = new DoubleAnimation(Element.ActualHeight, 0, new Duration(TimeSpan.FromMilliseconds(200)));\n\n            heightAnim.Completed += (S, E) =>\n            {\n                ItemsControl.Items.Remove(Element);\n\n                if (ItemsControl.Items.Count == 0)\n                {\n                    Hide();\n                }\n            };\n\n            opactityAnim.Completed += (S, E) => Element.BeginAnimation(HeightProperty, heightAnim);\n\n            transform.BeginAnimation(TranslateTransform.XProperty, translateAnim);\n            Element.BeginAnimation(OpacityProperty, opactityAnim);\n        }\n\n        const int MaxItems = 5;\n\n        public void Add(FrameworkElement Element)\n        {\n            if (Element is IRemoveRequester removeRequester)\n            {\n                removeRequester.RemoveRequested += () => Remove(Element);\n            }\n\n            if (Element is ScreenShotBalloon ssBalloon)\n                ssBalloon.Expander.IsExpanded = true;\n\n            foreach (var item in ItemsControl.Items)\n            {\n                if (item is ScreenShotBalloon screenShotBalloon)\n                {\n                    screenShotBalloon.Expander.IsExpanded = false;\n                }\n            }\n\n            ItemsControl.Items.Insert(0, Element);\n\n            if (ItemsControl.Items.Count > MaxItems)\n            {\n                var itemsToRemove = ItemsControl.Items\n                    .OfType<FrameworkElement>()\n                    .Skip(MaxItems)\n                    .ToArray();\n\n                foreach (var frameworkElement in itemsToRemove)\n                {\n                    if (frameworkElement is NotificationBalloon progressBalloon && !progressBalloon.Notification.Finished)\n                        continue;\n\n                    Remove(frameworkElement);\n                }\n            }\n        }\n\n        void NotificationStack_OnMouseMove(object Sender, MouseEventArgs E)\n        {\n            if (ItemsControl.Items.Count == 0)\n                return;\n\n            _lastMouseMoveTime = DateTime.Now;\n\n            Show();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Controls/OutputFolderControl.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.OutputFolderControl\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\">\n    <DockPanel>\n        <Button DockPanel.Dock=\"Left\"\n                Padding=\"5,0\"\n                VerticalContentAlignment=\"Center\"\n                ToolTip=\"{Binding OpenOutFolder, Source={StaticResource Loc}, Mode=OneWay}\"\n                Command=\"{Binding OpenOutputFolderCommand}\">\n            <DockPanel>\n                <Path Data=\"{Binding Icons.Folder, Source={StaticResource ServiceLocator}}\"\n                      Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"0,0,10,0\"\n                      Stretch=\"Uniform\"\n                      HorizontalAlignment=\"Center\"\n                      VerticalAlignment=\"Center\"/>\n\n                <TextBlock Text=\"{Binding OutFolder, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </DockPanel>\n        </Button>\n\n        <Button DockPanel.Dock=\"Right\"\n                ToolTip=\"{Binding SelectOutFolder, Source={StaticResource Loc}, Mode=OneWay}\"\n                Command=\"{Binding SelectOutputFolderCommand}\"\n                IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n            <Path Stretch=\"UniformToFill\"\n                  Height=\"4\"\n                  Width=\"16\"\n                  Data=\"{Binding Icons.More, Source={StaticResource ServiceLocator}}\"/>\n        </Button>\n        <Border ToolTip=\"{Binding MainViewModel.OutFolderDisplay.Value, Source={StaticResource ServiceLocator}}\"\n                IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                MouseUp=\"SelectTargetFolder\"\n                Cursor=\"Hand\">\n            <TextBox IsReadOnly=\"True\"\n                     IsEnabled=\"False\"\n                     Text=\"{Binding MainViewModel.OutFolderDisplay.Value, Source={StaticResource ServiceLocator}, Mode=OneWay}\"/>\n        </Border>\n    </DockPanel>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/OutputFolderControl.xaml.cs",
    "content": "﻿using System.Windows.Input;\nusing Captura.ViewModels;\n\nnamespace Captura\n{\n    public partial class OutputFolderControl\n    {\n        public OutputFolderControl()\n        {\n            InitializeComponent();\n        }\n\n        void SelectTargetFolder(object Sender, MouseButtonEventArgs E)\n        {\n            if (DataContext is MainViewModel vm)\n            {\n                vm.SelectOutputFolderCommand.ExecuteIfCan();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/PauseButton.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.PauseButton\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n             xmlns:local=\"clr-namespace:Captura\"\n             mc:Ignorable=\"d\" \n             d:DesignHeight=\"450\" d:DesignWidth=\"800\">\n    <local:ModernButton ToolTip=\"{Binding PauseResume, Source={StaticResource Loc}, Mode=OneWay}\" \n                        Command=\"{Binding RecordingViewModel.PauseCommand, Source={StaticResource ServiceLocator}}\"\n                        IconData=\"{Binding Icons.Pause, Source={StaticResource ServiceLocator}}\"\n                        Opacity=\"0.9\"\n                        RenderTransformOrigin=\"0.5,0.5\">\n        <local:ModernButton.RenderTransform>\n            <RotateTransform/>\n        </local:ModernButton.RenderTransform>\n        <local:ModernButton.Style>\n            <Style TargetType=\"local:ModernButton\"\n                   BasedOn=\"{StaticResource {x:Type local:ModernButton}}\">\n                <Style.Triggers>\n                    <DataTrigger Binding=\"{Binding RecordingViewModel.RecorderState.Value, Source={StaticResource ServiceLocator}}\" Value=\"Paused\">\n                        <DataTrigger.EnterActions>\n                            <BeginStoryboard>\n                                <Storyboard>\n                                    <DoubleAnimation Storyboard.TargetProperty=\"RenderTransform.Angle\"\n                                                     To=\"90\"\n                                                     Duration=\"0:0:0.15\"/>\n                                </Storyboard>\n                            </BeginStoryboard>\n                        </DataTrigger.EnterActions>\n                        <DataTrigger.ExitActions>\n                            <BeginStoryboard>\n                                <Storyboard>\n                                    <DoubleAnimation Storyboard.TargetProperty=\"RenderTransform.Angle\"\n                                                     To=\"0\"\n                                                     Duration=\"0:0:0.15\"/>\n                                </Storyboard>\n                            </BeginStoryboard>\n                        </DataTrigger.ExitActions>\n                    </DataTrigger>\n                </Style.Triggers>\n            </Style>\n        </local:ModernButton.Style>\n    </local:ModernButton>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/PauseButton.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class PauseButton\n    {\n        public PauseButton()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/PositionSettingsControl.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.PositionSettingsControl\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n             xmlns:viewModels=\"clr-namespace:Captura.ViewModels;assembly=Captura.ViewCore\"\n             xmlns:video=\"clr-namespace:Captura.Video;assembly=Captura.Base\"\n             mc:Ignorable=\"d\"\n             d:DataContext=\"{d:DesignInstance video:PositionedOverlaySettings}\">\n    <StackPanel>\n        <Grid>\n            <Grid.RowDefinitions>\n                <RowDefinition/>\n                <RowDefinition/>\n            </Grid.RowDefinitions>\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"*\"/>\n                <ColumnDefinition Width=\"*\"/>\n            </Grid.ColumnDefinitions>\n\n            <Label Content=\"X: \"\n                   Margin=\"0,3\"/>\n            <ComboBox ItemsSource=\"{x:Static viewModels:MainViewModel.XAlignments}\"\n                      SelectedValue=\"{Binding HorizontalAlignment, Mode=TwoWay}\"\n                      SelectedValuePath=\"Source\"\n                      DisplayMemberPath=\"Display\"\n                      Grid.Column=\"1\"\n                      Margin=\"3\"/>\n            <xctk:IntegerUpDown Value=\"{Binding X, Mode=TwoWay}\"\n                                Grid.Column=\"2\"\n                                Margin=\"0,3\"/>\n\n            <Label Content=\"Y: \"\n                   Grid.Row=\"1\"\n                   Margin=\"0,3\"/>\n            <ComboBox ItemsSource=\"{x:Static viewModels:MainViewModel.YAlignments}\"\n                      SelectedValue=\"{Binding VerticalAlignment, Mode=TwoWay}\"\n                      SelectedValuePath=\"Source\"\n                      DisplayMemberPath=\"Display\"\n                      Grid.Column=\"1\"\n                      Grid.Row=\"1\"\n                      Margin=\"3\"/>\n            <xctk:IntegerUpDown Value=\"{Binding Y, Mode=TwoWay}\"\n                                Grid.Column=\"2\"\n                                Grid.Row=\"1\"\n                                Margin=\"0,3\"/>\n        </Grid>\n    </StackPanel>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/PositionSettingsControl.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class PositionSettingsControl\n    {\n        public PositionSettingsControl()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/PuncturedRegion.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.PuncturedRegion\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             Visibility=\"Hidden\">\n    <Grid>\n        <Grid.Resources>\n            <SolidColorBrush Color=\"#77000000\" x:Key=\"SurroundColor\"/>\n            <Style TargetType=\"Border\">\n                <Setter Property=\"Background\" Value=\"{StaticResource SurroundColor}\"/>\n                <Setter Property=\"HorizontalAlignment\" Value=\"Left\"/>\n                <Setter Property=\"VerticalAlignment\" Value=\"Top\"/>\n            </Style>\n        </Grid.Resources>\n        \n        <Border Name=\"BorderTop\"/>\n        <Border Name=\"BorderBottom\"/>\n        <Border Name=\"BorderLeft\"/>\n        <Border Name=\"BorderRight\"/>\n    </Grid>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/PuncturedRegion.xaml.cs",
    "content": "﻿using System.Windows;\n\nnamespace Captura\n{\n    public partial class PuncturedRegion\n    {\n        public Rect? Region\n        {\n            get => (Rect?)GetValue(RegionProperty);\n            set => SetValue(RegionProperty, value);\n        }\n\n        public static readonly DependencyProperty RegionProperty = DependencyProperty.Register(\n            nameof(Region),\n            typeof(Rect?),\n            typeof(PuncturedRegion),\n            new PropertyMetadata(RegionChanged));\n\n        static void RegionChanged(DependencyObject Obj, DependencyPropertyChangedEventArgs E)\n        {\n             if (Obj is PuncturedRegion r)\n             {\n                switch (E.NewValue)\n                {\n                    case null:\n                        // Must not be collapsed, since ActualWidth and ActualHeight are used.\n                        r.Visibility = Visibility.Hidden;\n                        break;\n\n                    case Rect region:\n                        var w = r.ActualWidth;\n                        var h = r.ActualHeight;\n\n                        r.BorderTop.Margin = new Thickness();\n                        r.BorderTop.Width = w;\n                        r.BorderTop.Height = region.Top.Clip(0, h);\n\n                        r.BorderBottom.Margin = new Thickness(0, region.Bottom, 0, 0);\n                        r.BorderBottom.Width = w;\n                        r.BorderBottom.Height = (h - region.Bottom).Clip(0, h);\n\n                        r.BorderLeft.Margin = new Thickness(0, region.Top, 0, 0);\n                        r.BorderLeft.Width = region.Left.Clip(0, w);\n                        r.BorderLeft.Height = region.Height;\n\n                        r.BorderRight.Margin = new Thickness(region.Right, region.Top, 0, 0);\n                        r.BorderRight.Width = (w - region.Right).Clip(0, w);\n                        r.BorderRight.Height = region.Height;\n\n                        r.Visibility = Visibility.Visible;\n                        break;\n                }\n             }\n        }\n\n        public PuncturedRegion()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/RecentItem.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.RecentItem\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n             xmlns:models=\"clr-namespace:Captura.Models;assembly=Captura.Core\"\n             mc:Ignorable=\"d\"\n             d:DataContext=\"{d:DesignInstance models:FileRecentItem}\">\n    <DockPanel IsEnabled=\"{Binding IsSaving, Converter={StaticResource NegatingConverter}}\"\n               Margin=\"0,2\">\n        <Path Stretch=\"Uniform\"\n              Height=\"15\"\n              Width=\"15\"\n              Margin=\"0,0,5,0\"\n              Data=\"{Binding Icon}\"\n              Fill=\"{Binding IconColor}\"/>\n\n        <Button DockPanel.Dock=\"Right\"\n                ToolTip=\"{Binding RemoveFromList, Source={StaticResource Loc}, Mode=OneWay}\"\n                BorderBrush=\"Transparent\"\n                BorderThickness=\"0\"\n                Margin=\"5,0\"\n                Command=\"{Binding RemoveCommand}\">\n            <Path Stretch=\"UniformToFill\"\n                  Height=\"10\"\n                  Width=\"10\"\n                  Data=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"/>\n        </Button>\n\n        <Button Content=\"{Binding Display}\"\n                BorderThickness=\"0\"\n                HorizontalContentAlignment=\"Left\"\n                OverridesDefaultStyle=\"False\"\n                Command=\"{Binding ClickCommand}\">\n            <Button.ContextMenu>\n                <ContextMenu ItemsSource=\"{Binding Actions}\">\n                    <ContextMenu.ItemContainerStyle>\n                        <Style>\n                            <Setter Property=\"MenuItem.HeaderTemplate\">\n                                <Setter.Value>\n                                    <DataTemplate>\n                                        <DockPanel>\n                                            <Path Data=\"{Binding Icon}\"\n                                                  Width=\"15\"\n                                                  Height=\"15\"\n                                                  Margin=\"0,0,10,0\"\n                                                  Stretch=\"Uniform\"\n                                                  HorizontalAlignment=\"Center\"\n                                                  VerticalAlignment=\"Center\"/>\n\n                                            <TextBlock Text=\"{Binding Name}\"/>\n                                        </DockPanel>\n                                    </DataTemplate>\n                                </Setter.Value>\n                            </Setter>\n                            <Setter Property=\"MenuItem.Command\" Value=\"{Binding ClickCommand}\"/>\n                        </Style>\n                    </ContextMenu.ItemContainerStyle>\n                </ContextMenu>\n            </Button.ContextMenu>\n        </Button>\n    </DockPanel>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/RecentItem.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class RecentItem\n    {\n        public RecentItem()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/ScreenShotBalloon.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.ScreenShotBalloon\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:local=\"clr-namespace:Captura\"\n             BorderThickness=\"0,1,0,0\"\n             Padding=\"5,0,0,0\"\n             BorderBrush=\"{DynamicResource Accent}\">\n    <DockPanel>\n        <Expander IsExpanded=\"False\"\n                  Name=\"Expander\">\n            <Expander.HeaderTemplate>\n                <DataTemplate>\n                    <Grid HorizontalAlignment=\"{Binding Path=HorizontalAlignment, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Mode=OneWayToSource}\">\n                        <ContentPresenter Content=\"{Binding}\"/>\n                    </Grid>\n                </DataTemplate>\n            </Expander.HeaderTemplate>\n            <Expander.Header>\n                <DockPanel>\n                    <local:ModernButton ToolTip=\"{Binding Close, Source={StaticResource Loc}, Mode=OneWay}\"\n                                        Click=\"CloseButton_Click\"\n                                        Foreground=\"LightPink\"\n                                        IconData=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"\n                                        DockPanel.Dock=\"Right\"/>\n\n                    <local:ModernButton ToolTip=\"{Binding Edit, Source={StaticResource Loc}, Mode=OneWay}\"\n                                        Click=\"EditButton_OnClick\"\n                                        Foreground=\"{DynamicResource ItemText}\"\n                                        IconData=\"{Binding Icons.Pencil, Source={StaticResource ServiceLocator}}\"\n                                        DockPanel.Dock=\"Right\"/>\n\n                    <Label>\n                        <TextBlock Text=\"{Binding ScreenShotSaved, Source={StaticResource Loc}, Mode=OneWay}\"\n                                   VerticalAlignment=\"Center\"\n                                   Margin=\"5\"/>\n                    </Label>\n\n                    <Label>\n                        <TextBlock DockPanel.Dock=\"Bottom\"\n                                   Padding=\"5\"\n                                   VerticalAlignment=\"Center\">\n                            (<Run Text=\"{Binding Mode=OneWay}\"/>)\n                        </TextBlock>\n                    </Label>\n                </DockPanel>\n            </Expander.Header>\n\n            <Image Cursor=\"Hand\"\n                   MouseUp=\"Image_MouseUp\"\n                   Name=\"Img\"\n                   Margin=\"-6,0,-2,-1\"/>\n        </Expander>\n    </DockPanel>\n</UserControl>"
  },
  {
    "path": "src/Captura/Controls/ScreenShotBalloon.xaml.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Input;\nusing System.IO;\nusing System.Diagnostics;\nusing System;\nusing System.Windows.Media.Imaging;\nusing Captura.Models;\n\nnamespace Captura\n{\n    public partial class ScreenShotBalloon : IRemoveRequester\n    {\n        readonly string _filePath;\n\n        public ScreenShotBalloon(string FilePath)\n        {\n            _filePath = FilePath;\n            DataContext = Path.GetFileName(FilePath);\n\n            InitializeComponent();\n\n            // Do not assign image directly, cache it, else the file can't be deleted.\n            var image = new BitmapImage();\n            image.BeginInit();\n            image.CacheOption = BitmapCacheOption.OnLoad;\n            image.UriSource = new Uri(FilePath);\n            image.EndInit();\n            Img.Source = image;\n        }\n\n        void CloseButton_Click(object Sender, RoutedEventArgs E) => OnClose();\n\n        void OnClose()\n        {\n            RemoveRequested?.Invoke();\n        }\n\n        public event Action RemoveRequested;\n        \n        void Image_MouseUp(object Sender, MouseButtonEventArgs E)\n        {\n            ServiceProvider.LaunchFile(new ProcessStartInfo(_filePath));\n\n            OnClose();\n        }\n\n        void EditButton_OnClick(object Sender, RoutedEventArgs E)\n        {\n            var winserv = ServiceProvider.Get<IMainWindow>();\n            winserv.EditImage(_filePath);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Controls/ScreenShotButton.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.ScreenShotButton\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n             xmlns:local=\"clr-namespace:Captura\"\n             mc:Ignorable=\"d\"\n             d:DesignHeight=\"450\" d:DesignWidth=\"800\">\n    <local:ModernButton ToolTip=\"{Binding ScreenShot, Source={StaticResource Loc}, Mode=OneWay}\"\n                        Command=\"{Binding ScreenShotViewModel.ScreenShotCommand, Source={StaticResource ServiceLocator}}\"\n                        IconData=\"{Binding Icons.Camera, Source={StaticResource ServiceLocator}}\"\n                        Opacity=\"0.9\">\n        <local:ModernButton.ContextMenu>\n            <ContextMenu>\n                <MenuItem Header=\"ScreenShot (Region)\"\n                          Command=\"{Binding ScreenShotViewModel.ScreenshotRegionCommand, Source={StaticResource ServiceLocator}}\">\n                    <MenuItem.Icon>\n                        <Image Width=\"13\"\n                               Margin=\"5\">\n                            <Image.Source>\n                                <DrawingImage>\n                                    <DrawingImage.Drawing>\n                                        <GeometryDrawing Geometry=\"{Binding Icons.Crop, Source={StaticResource ServiceLocator}}\"\n                                                         Brush=\"{DynamicResource ItemText}\"/>\n                                    </DrawingImage.Drawing>\n                                </DrawingImage>\n                            </Image.Source>\n                        </Image>\n                    </MenuItem.Icon>\n                </MenuItem>\n\n                <MenuItem Header=\"ScreenShot (Screen)\"\n                          Command=\"{Binding ScreenShotViewModel.ScreenshotScreenCommand, Source={StaticResource ServiceLocator}}\">\n                    <MenuItem.Icon>\n                        <Image Width=\"13\"\n                               Margin=\"5\">\n                            <Image.Source>\n                                <DrawingImage>\n                                    <DrawingImage.Drawing>\n                                        <GeometryDrawing Geometry=\"{Binding Icons.Screen, Source={StaticResource ServiceLocator}}\"\n                                                         Brush=\"{DynamicResource ItemText}\"/>\n                                    </DrawingImage.Drawing>\n                                </DrawingImage>\n                            </Image.Source>\n                        </Image>\n                    </MenuItem.Icon>\n                </MenuItem>\n\n                <MenuItem Header=\"ScreenShot (Window)\"\n                          Command=\"{Binding ScreenShotViewModel.ScreenshotWindowCommand, Source={StaticResource ServiceLocator}}\">\n                    <MenuItem.Icon>\n                        <Image Width=\"13\"\n                               Margin=\"5\">\n                            <Image.Source>\n                                <DrawingImage>\n                                    <DrawingImage.Drawing>\n                                        <GeometryDrawing Geometry=\"{Binding Icons.Window, Source={StaticResource ServiceLocator}}\"\n                                                         Brush=\"{DynamicResource ItemText}\"/>\n                                    </DrawingImage.Drawing>\n                                </DrawingImage>\n                            </Image.Source>\n                        </Image>\n                    </MenuItem.Icon>\n                </MenuItem>\n            </ContextMenu>\n        </local:ModernButton.ContextMenu>\n    </local:ModernButton>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/ScreenShotButton.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class ScreenShotButton\n    {\n        public ScreenShotButton()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/StatusBar.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.StatusBar\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             DataContext=\"{Binding UpdateCheckerViewModel, Source={StaticResource ServiceLocator}}\">\n    <Grid>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition/>\n            <ColumnDefinition Width=\"Auto\"/>\n        </Grid.ColumnDefinitions>\n        <Grid.Resources>\n            <Style TargetType=\"Button\" BasedOn=\"{StaticResource {x:Type Button}}\">\n                <Setter Property=\"Background\" Value=\"Transparent\"/>\n                <Setter Property=\"HorizontalAlignment\" Value=\"Left\"/>\n                <Setter Property=\"BorderThickness\" Value=\"0\"/>\n                <Setter Property=\"Margin\" Value=\"0\"/>\n                <Setter Property=\"Padding\" Value=\"5,2\"/>\n            </Style>\n            <Style TargetType=\"Path\" BasedOn=\"{StaticResource {x:Type Path}}\">\n                <Setter Property=\"Margin\" Value=\"0,0,7,0\"/>\n                <Setter Property=\"Stretch\" Value=\"Uniform\"/>\n                <Setter Property=\"HorizontalAlignment\" Value=\"Center\"/>\n                <Setter Property=\"VerticalAlignment\" Value=\"Center\"/>\n            </Style>\n        </Grid.Resources>\n\n        <TextBlock Foreground=\"{DynamicResource Accent}\"\n                   Text=\"{Binding BuildName}\"\n                   VerticalAlignment=\"Center\"\n                   Grid.Column=\"1\"/>\n\n        <Button Grid.Column=\"0\"\n                Visibility=\"{Binding Checking, Converter={StaticResource BoolToVisibilityConverter}}\">\n            <DockPanel>\n                <Path Data=\"{Binding Icons.Refresh, Source={StaticResource ServiceLocator}}\"\n                      Width=\"15\"\n                      Height=\"15\"\n                      RenderTransformOrigin=\"0.5,0.5\">\n                    <Path.RenderTransform>\n                        <RotateTransform x:Name=\"CheckingRotater\"/>\n                    </Path.RenderTransform>\n                    <Path.Triggers>\n                        <EventTrigger RoutedEvent=\"Path.Loaded\">\n                            <BeginStoryboard>\n                                <Storyboard>\n                                    <DoubleAnimation Storyboard.TargetName=\"CheckingRotater\"\n                                                     Storyboard.TargetProperty=\"Angle\"\n                                                     From=\"0\"\n                                                     To=\"360\"\n                                                     RepeatBehavior=\"Forever\"/>\n                                </Storyboard>\n                            </BeginStoryboard>\n                        </EventTrigger>\n                    </Path.Triggers>\n                </Path>\n\n                <TextBlock Text=\"Checking for updates ...\"/>\n            </DockPanel>\n        </Button>\n\n        <Button Grid.Column=\"0\"\n                Command=\"{Binding CheckCommand}\"\n                ToolTip=\"Check Again\"\n                Visibility=\"{Binding CheckFailed, Converter={StaticResource BoolToVisibilityConverter}}\">\n            <Button.Content>\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.Error, Source={StaticResource ServiceLocator}}\"\n                          Width=\"12\"\n                          Height=\"12\"\n                          Fill=\"#b71c1c\"/>\n\n                    <TextBlock Text=\"Update Check Failed\"/>\n                </DockPanel>\n            </Button.Content>\n        </Button>\n\n        <Button Grid.Column=\"0\"\n                Command=\"{Binding GoToDownload}\">\n            <Button.Style>\n                <Style TargetType=\"Button\" BasedOn=\"{StaticResource {x:Type Button}}\">\n                    <Setter Property=\"Visibility\" Value=\"Collapsed\"/>\n                    <Style.Triggers>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding Checking}\" Value=\"False\"/>\n                                <Condition Binding=\"{Binding CheckFailed}\" Value=\"False\"/>\n                                <Condition Binding=\"{Binding UpdateAvailable}\" Value=\"True\"/>\n                            </MultiDataTrigger.Conditions>\n\n                            <Setter Property=\"Visibility\" Value=\"Visible\"/>\n                        </MultiDataTrigger>\n                    </Style.Triggers>\n                </Style>\n            </Button.Style>\n            <Button.Content>\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.Download, Source={StaticResource ServiceLocator}}\"\n                          Width=\"12\"\n                          Height=\"12\"/>\n\n                    <TextBlock>\n                        Update Available (<Run Text=\"{Binding NewVersion, Mode=OneWay}\"/>)\n                    </TextBlock>\n                </DockPanel>\n            </Button.Content>\n        </Button>\n\n        <Button Grid.Column=\"0\"\n                Command=\"{Binding CheckCommand}\"\n                ToolTip=\"Check Again\">\n            <Button.Style>\n                <Style TargetType=\"Button\" BasedOn=\"{StaticResource {x:Type Button}}\">\n                    <Setter Property=\"Visibility\" Value=\"Collapsed\"/>\n                    <Style.Triggers>\n                        <MultiDataTrigger>\n                            <MultiDataTrigger.Conditions>\n                                <Condition Binding=\"{Binding Checking}\" Value=\"False\"/>\n                                <Condition Binding=\"{Binding CheckFailed}\" Value=\"False\"/>\n                                <Condition Binding=\"{Binding UpdateAvailable}\" Value=\"False\"/>\n                            </MultiDataTrigger.Conditions>\n\n                            <Setter Property=\"Visibility\" Value=\"Visible\"/>\n                        </MultiDataTrigger>\n                    </Style.Triggers>\n                </Style>\n            </Button.Style>\n            <Button.Content>\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.Check, Source={StaticResource ServiceLocator}}\"\n                          Width=\"10\"\n                          Height=\"12\"\n                          Fill=\"LimeGreen\"/>\n\n                    <TextBlock Text=\"Up to date\"/>\n                </DockPanel>\n            </Button.Content>\n        </Button>\n    </Grid>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/StatusBar.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class StatusBar\n    {\n        public StatusBar()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/StripedBorder.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.StripedBorder\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\n    <DockPanel>\n        <DockPanel.Resources>\n            <Style TargetType=\"Border\">\n                <Setter Property=\"BorderBrush\">\n                    <Setter.Value>\n                        <DrawingBrush TileMode=\"Tile\"\n                                      Viewport=\"0,0,20,20\"\n                                      ViewportUnits=\"Absolute\">\n                            <DrawingBrush.Drawing>\n                                <DrawingGroup>\n                                    <GeometryDrawing>\n                                        <GeometryDrawing.Brush>\n                                            <SolidColorBrush Color=\"{DynamicResource WindowBackgroundColor}\"/>\n                                        </GeometryDrawing.Brush>\n                                        <GeometryDrawing.Geometry>\n                                            <GeometryGroup>\n                                                <RectangleGeometry Rect=\"0,0,10,10\" />\n                                                <RectangleGeometry Rect=\"10,10,10,10\" />\n                                            </GeometryGroup>\n                                        </GeometryDrawing.Geometry>\n                                    </GeometryDrawing>\n\n                                    <GeometryDrawing>\n                                        <GeometryDrawing.Brush>\n                                            <SolidColorBrush Color=\"{DynamicResource AccentColor}\"/>\n                                        </GeometryDrawing.Brush>\n                                        <GeometryDrawing.Geometry>\n                                            <GeometryGroup>\n                                                <RectangleGeometry Rect=\"10,0,10,10\" />\n                                                <RectangleGeometry Rect=\"0,10,10,10\" />\n                                            </GeometryGroup>\n                                        </GeometryDrawing.Geometry>\n                                    </GeometryDrawing>\n                                </DrawingGroup>\n                            </DrawingBrush.Drawing>\n                        </DrawingBrush>\n                    </Setter.Value>\n                </Setter>\n            </Style>\n        </DockPanel.Resources>\n\n        <Border BorderThickness=\"1,0\"/>\n\n        <Border BorderThickness=\"1,0\"\n                DockPanel.Dock=\"Right\"/>\n\n        <Border BorderThickness=\"0,1\"\n                DockPanel.Dock=\"Bottom\"/>\n\n        <Border BorderThickness=\"0,1\"\n                DockPanel.Dock=\"Top\"/>\n    </DockPanel>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/StripedBorder.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class StripedBorder\n    {\n        public StripedBorder()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/TextOverlaySettingsControl.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.TextOverlaySettingsControl\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:local=\"clr-namespace:Captura\"\n             xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n             xmlns:video=\"clr-namespace:Captura.Video;assembly=Captura.Base\"\n             mc:Ignorable=\"d\"\n             d:DataContext=\"{d:DesignInstance video:TextOverlaySettings}\">\n    <StackPanel>\n        <Grid>\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"*\"/>\n                <ColumnDefinition Width=\"70\"/>\n                <ColumnDefinition Width=\"40\"/>\n            </Grid.ColumnDefinitions>\n            \n            <Path Data=\"{Binding Icons.Font, Source={StaticResource ServiceLocator}}\"\n                  Width=\"15\"\n                  Height=\"15\"\n                  Stretch=\"Uniform\"\n                  HorizontalAlignment=\"Center\"\n                  VerticalAlignment=\"Center\"\n                  ToolTip=\"Font\"/>\n\n            <local:FontSelector Grid.Column=\"1\"\n                                Margin=\"10,5,5,5\"\n                                SelectedFont=\"{Binding FontFamily, Mode=TwoWay}\"/>\n\n            <xctk:IntegerUpDown Minimum=\"1\"\n                                Value=\"{Binding FontSize, Mode=TwoWay}\"\n                                Grid.Column=\"2\"\n                                Margin=\"0,5\"\n                                ToolTip=\"{Binding FontSize, Source={StaticResource Loc}, Mode=OneWay}\"/>\n\n            <xctk:ColorPicker SelectedColor=\"{Binding FontColor, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                              Grid.Column=\"3\"\n                              Margin=\"0,5\"\n                              ToolTip=\"{Binding Color, Source={StaticResource Loc}, Mode=OneWay}\"/>\n        </Grid>\n        \n        <DockPanel>\n            <Label Content=\"{Binding BackColor, Source={StaticResource Loc}, Mode=OneWay}\"\n                   ContentStringFormat=\"{}{0}: \"\n                   Margin=\"0,5,5,5\"/>\n\n            <xctk:ColorPicker SelectedColor=\"{Binding BackgroundColor, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                              Margin=\"0,5\"/>\n        </DockPanel>\n\n        <Grid>\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"*\"/>\n                <ColumnDefinition Width=\"*\"/>\n            </Grid.ColumnDefinitions>\n\n            <Path Data=\"{Binding Icons.Border, Source={StaticResource ServiceLocator}}\"\n                  Width=\"15\"\n                  Height=\"15\"\n                  Margin=\"0,0,10,0\"\n                  Stretch=\"Uniform\"\n                  HorizontalAlignment=\"Center\"\n                  VerticalAlignment=\"Center\"/>\n\n            <Label Content=\"Border\"\n                   Grid.Column=\"1\"\n                   ContentStringFormat=\"{}{0}: \"/>\n\n            <xctk:IntegerUpDown Value=\"{Binding BorderThickness, Mode=TwoWay}\"\n                                Grid.Column=\"2\"\n                                Margin=\"5\"\n                                ToolTip=\"{Binding BorderThickness, Source={StaticResource Loc}, Mode=OneWay}\"/>\n\n            <xctk:ColorPicker SelectedColor=\"{Binding BorderColor, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                              Grid.Column=\"3\"\n                              Margin=\"0,5\"\n                              ToolTip=\"{Binding BorderColor, Source={StaticResource Loc}, Mode=OneWay}\"/>\n        </Grid>\n\n        <Grid>\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"*\"/>\n                <ColumnDefinition Width=\"*\"/>\n            </Grid.ColumnDefinitions>\n\n            <Label Content=\"{Binding Padding, Source={StaticResource Loc}, Mode=OneWay}\"\n                   ContentStringFormat=\"{}{0} (X, Y): \"\n                   Margin=\"0,5\"/>\n\n            <xctk:IntegerUpDown Value=\"{Binding HorizontalPadding, Mode=TwoWay}\"\n                                Grid.Column=\"1\"\n                                Margin=\"5\"/>\n\n            <xctk:IntegerUpDown Value=\"{Binding VerticalPadding, Mode=TwoWay}\"\n                                Grid.Column=\"2\"\n                                Margin=\"0,5\"/>\n        </Grid>\n\n        <DockPanel>\n            <Path Data=\"{Binding Icons.RoundCorner, Source={StaticResource ServiceLocator}}\"\n                  Width=\"15\"\n                  Height=\"15\"\n                  Margin=\"0,0,10,0\"\n                  Stretch=\"Uniform\"\n                  HorizontalAlignment=\"Center\"\n                  VerticalAlignment=\"Center\"/>\n            \n            <Label Content=\"{Binding CornerRadius, Source={StaticResource Loc}, Mode=OneWay}\"\n                   ContentStringFormat=\"{}{0}: \"\n                   Margin=\"0,5,5,5\"/>\n\n            <xctk:IntegerUpDown Value=\"{Binding CornerRadius, Mode=TwoWay}\"\n                                Margin=\"0,5\"/>\n        </DockPanel>\n\n        <local:PositionSettingsControl/>\n    </StackPanel>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/TextOverlaySettingsControl.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class TextOverlaySettingsControl\n    {\n        public TextOverlaySettingsControl()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Controls/VideoSourceKindList.xaml",
    "content": "﻿<UserControl x:Class=\"Captura.VideoSourceKindList\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\n    <ListView Margin=\"2,5\"\n              IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n              ItemsSource=\"{Binding VideoSourcesViewModel.VideoSources, Source={StaticResource ServiceLocator}}\"\n              SelectedValue=\"{Binding VideoSourcesViewModel.SelectedVideoSourceKind, Mode=TwoWay, Delay=10, Source={StaticResource ServiceLocator}}\"\n              BorderThickness=\"0.7\"\n              SelectionMode=\"Single\">\n        <ListView.Template>\n            <ControlTemplate TargetType=\"ListView\">\n                <Border CornerRadius=\"15\"\n                        BorderThickness=\"{TemplateBinding BorderThickness}\"\n                        BorderBrush=\"{TemplateBinding BorderBrush}\">\n                    <Border.OpacityMask>\n                        <VisualBrush>\n                            <VisualBrush.Visual>\n                                <Border SnapsToDevicePixels=\"True\"\n                                        Background=\"Black\"\n                                        CornerRadius=\"{Binding CornerRadius, RelativeSource={RelativeSource AncestorType=Border}}\"\n                                        Width=\"{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Border}}\"\n                                        Height=\"{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Border}}\"/>\n                            </VisualBrush.Visual>\n                        </VisualBrush>\n                    </Border.OpacityMask>\n                    <ItemsPresenter></ItemsPresenter>\n                </Border>\n            </ControlTemplate>\n        </ListView.Template>\n        <ListView.ItemsPanel>\n            <ItemsPanelTemplate>\n                <UniformGrid Rows=\"1\"/>\n            </ItemsPanelTemplate>\n        </ListView.ItemsPanel>\n        <ListView.ItemTemplate>\n            <DataTemplate>\n                <Grid Background=\"#01000000\">\n                    <Grid.ToolTip>\n                        <StackPanel MinWidth=\"200\">\n                            <TextBlock Text=\"{Binding Name, Mode=OneWay}\"\n                                       FontWeight=\"Bold\"/>\n\n                            <TextBlock Text=\"{Binding Description, Mode=OneWay}\"/>\n                        </StackPanel>\n                    </Grid.ToolTip>\n                    <Path Data=\"{Binding Icon}\"\n                          Style=\"{DynamicResource VideoSourceIcon}\"/>\n                </Grid>\n                <DataTemplate.Triggers>\n                    <MultiDataTrigger>\n                        <MultiDataTrigger.Conditions>\n                            <Condition Binding=\"{Binding SupportsStepsMode}\" Value=\"False\"/>\n                            <Condition Binding=\"{Binding ViewConditions.IsStepsMode.Value, Source={StaticResource ServiceLocator}}\" Value=\"True\"/>\n                        </MultiDataTrigger.Conditions>\n                        <Setter Property=\"IsEnabled\" Value=\"False\"/>\n                    </MultiDataTrigger>\n                </DataTemplate.Triggers>\n            </DataTemplate>\n        </ListView.ItemTemplate>\n        <ListView.ItemContainerStyle>\n            <Style TargetType=\"ListViewItem\" BasedOn=\"{StaticResource {x:Type ListViewItem}}\">\n                <EventSetter Event=\"PreviewMouseLeftButtonDown\" Handler=\"OnVideoSourceReSelect\"/>\n            </Style>\n        </ListView.ItemContainerStyle>\n    </ListView>\n</UserControl>\n"
  },
  {
    "path": "src/Captura/Controls/VideoSourceKindList.xaml.cs",
    "content": "﻿using System.Windows.Controls;\nusing System.Windows.Input;\nusing Captura.Video;\n\nnamespace Captura\n{\n    public partial class VideoSourceKindList\n    {\n        public VideoSourceKindList()\n        {\n            InitializeComponent();\n        }\n\n        void OnVideoSourceReSelect(object Sender, MouseButtonEventArgs E)\n        {\n            if (Sender is ListViewItem item && item.IsSelected)\n            {\n                if (item.DataContext is IVideoSourceProvider provider)\n                {\n                    provider.OnSelect();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Models/AudioPlayer.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Windows.Media;\n\nnamespace Captura.Audio\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class AudioPlayer : IAudioPlayer\n    {\n        readonly SoundSettings _settings;\n        readonly MediaPlayer _mediaPlayer;\n\n        public AudioPlayer(SoundSettings Settings)\n        {\n            _settings = Settings;\n            _mediaPlayer = new MediaPlayer();\n        }\n\n        void PlaySound(string Path)\n        {\n            if (!File.Exists(Path))\n                return;\n\n            _mediaPlayer.Open(new Uri(Path));\n            _mediaPlayer.Play();\n        }\n\n        public void Play(SoundKind SoundKind)\n        {\n            if (_settings.Items.TryGetValue(SoundKind, out var value))\n                PlaySound(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Models/CmdOptions.cs",
    "content": "﻿using CommandLine;\n\nnamespace Captura\n{\n    /// <summary>\n    /// Command-line options for the WPF app.\n    /// </summary>\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class CmdOptions\n    {\n        [Option(\"reset\", HelpText = \"Reset all setting values to default.\")]\n        public bool Reset { get; set; }\n\n        [Option(\"tray\", HelpText = \"Start minimized into the system tray.\")]\n        public bool Tray { get; set; }\n        \n        [Option(\"no-hotkey\", HelpText = \"Do not Register hotkeys.\")]\n        public bool NoHotkeys { get; set; }\n\n        [Option(\"no-persist\", HelpText = \"Do not save any changes in settings.\")]\n        public bool NoPersist { get; set; }\n\n        [Option(\"settings\", HelpText = \"Settings Directory\")]\n        public string Settings { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Models/Dpi.cs",
    "content": "﻿using System.Windows.Interop;\n\nnamespace Captura\n{\n    /// <summary>\n    /// Provides DPI scaling factor.\n    /// Only needs to be used when dealing with WPF since their sizes are specified in Device Independent Pixels.\n    /// </summary>\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class Dpi\n    {\n        static Dpi()\n        {\n            using var src = new HwndSource(new HwndSourceParameters());\n            if (src.CompositionTarget != null)\n            {\n                var matrix = src.CompositionTarget.TransformToDevice;\n\n                X = (float) matrix.M11;\n                Y = (float) matrix.M22;\n            }\n        }\n\n        public static float X { get; }\n\n        public static float Y { get; }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Models/FFmpegViewsProvider.cs",
    "content": "﻿using System.Windows;\nusing Captura.Audio;\nusing Captura.Loc;\nusing Captura.Models;\nusing Captura.Views;\nusing FirstFloor.ModernUI.Windows.Controls;\n\nnamespace Captura.FFmpeg\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FFmpegViewsProvider : IFFmpegViewsProvider\n    {\n        readonly ILocalizationProvider _loc;\n        readonly IAudioPlayer _audioPlayer;\n        readonly FFmpegSettings _settings;\n        readonly IDialogService _dialogService;\n\n        public FFmpegViewsProvider(ILocalizationProvider Loc,\n            IAudioPlayer AudioPlayer,\n            FFmpegSettings Settings,\n            IDialogService DialogService)\n        {\n            _loc = Loc;\n            _audioPlayer = AudioPlayer;\n            _settings = Settings;\n            _dialogService = DialogService;\n        }\n\n        public void ShowLogs()\n        {\n            SettingsWindow.ShowFFmpegLogs();\n        }\n\n        public void ShowUnavailable()\n        {\n            Application.Current.Dispatcher.Invoke(() =>\n            {\n                var dialog = new ModernDialog\n                {\n                    Title = \"FFmpeg Unavailable\",\n                    Content = \"FFmpeg was not found on your system.\\n\\nSelect FFmpeg Folder if you alrady have FFmpeg on your system, else Download FFmpeg.\"\n                };\n\n                // Yes -> Select FFmpeg Folder\n                dialog.YesButton.Content = _loc.SelectFFmpegFolder;\n                dialog.YesButton.Click += (S, E) => PickFolder();\n\n                // No -> Download FFmpeg\n                dialog.NoButton.Content = _loc.DownloadFFmpeg;\n                dialog.NoButton.Click += (S, E) => ShowDownloader();\n\n                dialog.CancelButton.Content = \"Cancel\";\n\n                dialog.Buttons = new[] { dialog.YesButton, dialog.NoButton, dialog.CancelButton };\n\n                _audioPlayer.Play(SoundKind.Error);\n\n                dialog.ShowDialog();\n            });\n        }\n\n        public void ShowDownloader()\n        {\n            FFmpegDownloaderWindow.ShowInstance();\n        }\n\n        public void PickFolder()\n        {\n            var folder = _dialogService.PickFolder(_settings.GetFolderPath(), _loc.SelectFFmpegFolder);\n\n            if (!string.IsNullOrWhiteSpace(folder))\n                _settings.FolderPath = folder;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Models/HitType.cs",
    "content": "﻿namespace Captura\n{\n    enum HitType\n    {\n        None,\n        Body,\n        Left,\n        Right,\n        Top,\n        Bottom,\n        UpperLeft,\n        UpperRight,\n        LowerRight,\n        LowerLeft\n    }\n}"
  },
  {
    "path": "src/Captura/Models/HotkeyListener.cs",
    "content": "﻿using System;\nusing System.Windows.Interop;\n\nnamespace Captura.Hotkeys\n{\n    public class HotkeyListener : IHotkeyListener\n    {\n        const int WindowsMessageHotkey = 786;\n\n        public HotkeyListener()\n        {\n            ComponentDispatcher.ThreadPreprocessMessage += (ref MSG Message, ref bool Handled) =>\n            {\n                if (Message.message == WindowsMessageHotkey)\n                {\n                    var id = Message.wParam.ToInt32();\n\n                    HotkeyReceived?.Invoke(id);\n                }\n            };\n        }\n\n        public event Action<int> HotkeyReceived;\n    }\n}"
  },
  {
    "path": "src/Captura/Models/HotkeySetup.cs",
    "content": "﻿using System.Linq;\nusing Captura.Models;\n\nnamespace Captura.Hotkeys\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class HotkeySetup\n    {\n        readonly HotKeyManager _hotKeyManager;\n        readonly IMessageProvider _messageProvider;\n\n        public HotkeySetup(HotKeyManager HotKeyManager,\n            IMessageProvider MessageProvider)\n        {\n            _hotKeyManager = HotKeyManager;\n            _messageProvider = MessageProvider;\n        }\n\n        public void Setup()\n        {\n            _hotKeyManager.RegisterAll();\n        }\n\n        public void ShowUnregistered()\n        {\n            var notRegisteredOnStartup = _hotKeyManager\n                .Hotkeys\n                .Where(M => M.IsActive && !M.IsRegistered)\n                .ToArray();\n\n            if (notRegisteredOnStartup.Length <= 0)\n                return;\n\n            var message = \"The following Hotkeys could not be registered:\\nOther programs might be using them.\\nTry changing them.\\n\\n\";\n\n            foreach (var hotkey in notRegisteredOnStartup)\n            {\n                message += $\"{hotkey.Service.Description} - {hotkey}\\n\\n\";\n            }\n\n            _messageProvider.ShowError(message, \"Failed to Register Hotkeys\");\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Models/HotkeyViewActor.cs",
    "content": "﻿namespace Captura.Hotkeys\n{\n    public class HotkeyViewActor : IHotkeyActor\n    {\n        public void Act(ServiceName Service)\n        {\n            switch (Service)\n            {\n                case ServiceName.ShowMainWindow:\n                    MainWindow.Instance.ShowAndFocus();\n                    break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Models/IRemoveRequester.cs",
    "content": "﻿using System;\n\nnamespace Captura\n{\n    public interface IRemoveRequester\n    {\n        event Action RemoveRequested;\n    }\n}"
  },
  {
    "path": "src/Captura/Models/MainModule.cs",
    "content": "﻿using System;\nusing Captura.Audio;\nusing Captura.FFmpeg;\nusing Captura.Hotkeys;\nusing Captura.Models;\nusing Captura.Video;\nusing Captura.ViewModels;\nusing Hardcodet.Wpf.TaskbarNotification;\n\nnamespace Captura\n{\n    public class MainModule : IModule\n    {\n        public void OnLoad(IBinder Binder)\n        {\n            // Use singleton to ensure the same instance is used every time.\n            Binder.Bind<IMessageProvider, MessageProvider>();\n            Binder.Bind<IRegionProvider, RegionSelectorProvider>();\n            Binder.Bind<ISystemTray, SystemTray>();\n            Binder.Bind<IPreviewWindow, PreviewWindowService>();\n            Binder.Bind<IVideoSourcePicker, VideoSourcePicker>();\n            Binder.Bind<IAudioPlayer, AudioPlayer>();\n            Binder.Bind<IFFmpegViewsProvider, FFmpegViewsProvider>();\n\n            Binder.Bind<IHotkeyListener, HotkeyListener>();\n            Binder.Bind<IHotkeyActor, HotkeyViewActor>();\n            \n            Binder.BindSingleton<AboutViewModel>();\n            Binder.BindSingleton<RegionSelectorViewModel>();\n\n            Binder.BindSingleton<WebcamPage>();\n\n            // Bind as a Function to ensure the UI objects are referenced only after they have been created.\n            Binder.Bind<Func<TaskbarIcon>>(() => () => MainWindow.Instance.SystemTray);\n            Binder.Bind<IMainWindow>(() => new MainWindowProvider(() => MainWindow.Instance));\n        }\n\n        public void Dispose() { }\n    }\n}"
  },
  {
    "path": "src/Captura/Models/MainWindowHelper.cs",
    "content": "﻿using Captura.Hotkeys;\nusing Captura.ViewModels;\n\nnamespace Captura\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class MainWindowHelper\n    {\n        public MainWindowHelper(MainViewModel MainViewModel,\n            HotkeySetup HotkeySetup,\n            TimerModel TimerModel,\n            Settings Settings,\n            RecordingViewModel RecordingViewModel)\n        {\n            this.MainViewModel = MainViewModel;\n            this.HotkeySetup = HotkeySetup;\n            this.TimerModel = TimerModel;\n            this.Settings = Settings;\n            this.RecordingViewModel = RecordingViewModel;\n        }\n\n        public MainViewModel MainViewModel { get; }\n\n        public HotkeySetup HotkeySetup { get; }\n\n        public TimerModel TimerModel { get; }\n\n        public Settings Settings { get; }\n\n        public RecordingViewModel RecordingViewModel { get; }\n    }\n}"
  },
  {
    "path": "src/Captura/Models/MainWindowProvider.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Windows;\nusing Captura.Views;\n\nnamespace Captura.Models\n{\n    class MainWindowProvider : IMainWindow\n    {\n        readonly Func<Window> _window;\n\n        public MainWindowProvider(Func<Window> Window)\n        {\n            _window = Window;\n        }\n\n        public bool IsVisible\n        {\n            get => _window.Invoke().IsVisible;\n            set\n            {\n                if (value)\n                    _window.Invoke().Show();\n                else _window.Invoke().Hide();\n            }\n        }\n\n        public bool IsMinimized\n        {\n            get => _window.Invoke().WindowState == WindowState.Minimized;\n            set => _window.Invoke().WindowState = value ? WindowState.Minimized : WindowState.Normal;\n        }\n\n        public void EditImage(string FileName)\n        {\n            var settings = ServiceProvider.Get<Settings>().ScreenShots;\n            Process.Start(settings.ExternalEditor, $\"\\\"{FileName}\\\"\");\n        }\n\n        public void TrimMedia(string FileName)\n        {\n            var win = new TrimmerWindow();\n\n            win.Open(FileName);\n\n            win.ShowAndFocus();\n        }\n\n        public void UploadToYouTube(string FileName)\n        {\n            var win = new YouTubeUploaderWindow();\n\n            win.Open(FileName);\n\n            win.ShowAndFocus();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Models/MessageProvider.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Media;\nusing Captura.Audio;\nusing Captura.Loc;\nusing Captura.Views;\nusing FirstFloor.ModernUI.Windows.Controls;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class MessageProvider : IMessageProvider\n    {\n        readonly IAudioPlayer _audioPlayer;\n        readonly ILocalizationProvider _loc;\n\n        public MessageProvider(IAudioPlayer AudioPlayer, ILocalizationProvider Loc)\n        {\n            _audioPlayer = AudioPlayer;\n            _loc = Loc;\n        }\n\n        public void ShowError(string Message, string Header = null)\n        {\n            Application.Current.Dispatcher.Invoke(() =>\n            {\n                var dialog = new ModernDialog\n                {\n                    Title = _loc.ErrorOccurred,\n                    Content = new StackPanel\n                    {\n                        Children =\n                        {\n                            new TextBlock\n                            {\n                                Text = Header,\n                                Margin = new Thickness(0, 0, 0, 10),\n                                FontSize = 15\n                            },\n\n                            new ScrollViewer\n                            {\n                                Content = Message,\n                                HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,\n                                Padding = new Thickness(0, 0, 0, 10)\n                            }\n                        }\n                    }\n                };\n\n                dialog.OkButton.Content = _loc.Ok;\n                dialog.Buttons = new[] { dialog.OkButton };\n\n                dialog.BackgroundContent = new Grid\n                {\n                    Background = new SolidColorBrush(Color.FromArgb(255, 244, 67, 54)),\n                    VerticalAlignment = VerticalAlignment.Top,\n                    Height = 10\n                };\n\n                _audioPlayer.Play(SoundKind.Error);\n\n                dialog.ShowDialog();\n            });\n        }\n\n        public void ShowException(Exception Exception, string Message, bool Blocking = false)\n        {\n            Application.Current.Dispatcher.Invoke(() =>\n            {\n                var win = new ErrorWindow(Exception, Message);\n\n                _audioPlayer.Play(SoundKind.Error);\n\n                if (Blocking)\n                {\n                    win.ShowDialog();\n                }\n                else win.ShowAndFocus();\n            });\n        }\n\n        public bool ShowYesNo(string Message, string Title)\n        {\n            return Application.Current.Dispatcher.Invoke(() =>\n            {\n                var dialog = new ModernDialog\n                {\n                    Title = Title,\n                    Content = new ScrollViewer\n                    {\n                        Content = Message,\n                        HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,\n                        Padding = new Thickness(0, 0, 0, 10)\n                    }\n                };\n\n                var result = false;\n\n                dialog.YesButton.Content = _loc.Yes;\n                dialog.YesButton.Click += (S, E) => result = true;\n\n                dialog.NoButton.Content = _loc.No;\n\n                dialog.Buttons = new[] { dialog.YesButton, dialog.NoButton };\n\n                dialog.ShowDialog();\n\n                return result;\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Models/PreviewWindowService.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Windows.Interop;\nusing Captura.Windows.DirectX;\nusing Captura.Windows.Gdi;\nusing Reactive.Bindings.Extensions;\nusing SharpDX.Direct3D9;\n\nnamespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class PreviewWindowService : IPreviewWindow\n    {\n        D3D9PreviewAssister _d3D9PreviewAssister;\n        IntPtr _backBufferPtr;\n        Texture _texture;\n        readonly VisualSettings _visualSettings;\n\n        public void Show()\n        {\n            _visualSettings.Expanded = true;\n        }\n\n        public bool IsVisible { get; private set; }\n\n        public PreviewWindowService(VisualSettings VisualSettings)\n        {\n            _visualSettings = VisualSettings;\n\n            VisualSettings.ObserveProperty(M => M.Expanded)\n                .Subscribe(M => IsVisible = M);\n        }\n\n        IBitmapFrame _lastFrame;\n\n        public void Display(IBitmapFrame Frame)\n        {\n            if (Frame is RepeatFrame)\n                return;\n\n            if (!IsVisible)\n            {\n                Frame.Dispose();\n                return;\n            }\n\n            var win = MainWindow.Instance;\n\n            win.Dispatcher.Invoke(() =>\n            {\n                win.DisplayImage.Image = null;\n\n                _lastFrame?.Dispose();\n                _lastFrame = Frame;\n\n                Frame = Frame.Unwrap();\n\n                switch (Frame)\n                {\n                    case DrawingFrame drawingFrame:\n                        try\n                        {\n                            // TODO: Preview is not shown during Webcam only recordings\n                            // This check swallows errors\n                            var h = drawingFrame.Bitmap.Height;\n\n                            if (h == 0)\n                                return;\n                        }\n                        catch { return; }\n\n                        win.WinFormsHost.Visibility = Visibility.Visible;\n                        win.DisplayImage.Image = drawingFrame.Bitmap;\n                        break;\n\n                    case Texture2DFrame texture2DFrame:\n                        win.WinFormsHost.Visibility = Visibility.Collapsed;\n                        if (_d3D9PreviewAssister == null)\n                        {\n                            _d3D9PreviewAssister = new D3D9PreviewAssister(ServiceProvider.Get<IPlatformServices>());\n                            _texture = _d3D9PreviewAssister.GetSharedTexture(texture2DFrame.PreviewTexture);\n\n                            using var surface = _texture.GetSurfaceLevel(0);\n                            _backBufferPtr = surface.NativePointer;\n                        }\n\n                        Invalidate(_backBufferPtr, texture2DFrame.Width, texture2DFrame.Height);\n                        break;\n                }\n            });\n        }\n\n        void Invalidate(IntPtr BackBufferPtr, int Width, int Height)\n        {\n            var win = MainWindow.Instance;\n\n            win.D3DImage.Lock();\n            win.D3DImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, BackBufferPtr);\n\n            if (BackBufferPtr != IntPtr.Zero)\n                win.D3DImage.AddDirtyRect(new Int32Rect(0, 0, Width, Height));\n\n            win.D3DImage.Unlock();\n        }\n\n        public void Dispose()\n        {\n            var win = MainWindow.Instance;\n\n            win.Dispatcher.Invoke(() =>\n            {\n                win.DisplayImage.Image = null;\n                win.WinFormsHost.Visibility = Visibility.Collapsed;\n\n                _lastFrame?.Dispose();\n                _lastFrame = null;\n\n                if (_d3D9PreviewAssister != null)\n                {\n                    Invalidate(IntPtr.Zero, 0, 0);\n\n                    _texture.Dispose();\n\n                    _d3D9PreviewAssister.Dispose();\n\n                    _d3D9PreviewAssister = null;\n                }\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Models/RegionSelectorProvider.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Windows;\nusing Captura.ViewModels;\n\nnamespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class RegionSelectorProvider : IRegionProvider\n    {\n        readonly Lazy<RegionSelector> _regionSelector;\n        readonly RegionItem _regionItem;\n        readonly RegionSelectorViewModel _viewModel;\n\n        public RegionSelectorProvider(RegionSelectorViewModel ViewModel,\n            IPlatformServices PlatformServices)\n        {\n            _viewModel = ViewModel;\n\n            _regionSelector = new Lazy<RegionSelector>(() => new RegionSelector(ViewModel));\n\n            _regionItem = new RegionItem(this, PlatformServices);\n        }\n\n        public bool SelectorVisible\n        {\n            get => _regionSelector.Value.Visibility == Visibility.Visible;\n            set\n            {\n                if (value)\n                    _regionSelector.Value.Show();\n                else _regionSelector.Value.Hide();\n            }\n        }\n\n        public Rectangle SelectedRegion\n        {\n            get => _viewModel.SelectedRegion;\n            set => _viewModel.SelectedRegion = value;\n        }\n\n        public IVideoItem VideoSource => _regionItem;\n\n        public IntPtr Handle => _regionSelector.Value.Handle;\n    }\n}"
  },
  {
    "path": "src/Captura/Models/ServiceLocator.cs",
    "content": "﻿using Captura.Models;\nusing Captura.MouseKeyHook;\nusing Captura.ViewModels;\nusing Captura.Webcam;\n\n// ReSharper disable MemberCanBeMadeStatic.Global\n\nnamespace Captura\n{\n    /// <summary>\n    /// Used as a Static Resource to inject ViewModels into UI.\n    /// </summary>\n    public class ServiceLocator\n    {\n        static ServiceLocator()\n        {\n            ServiceProvider.LoadModule(new MainModule());\n        }\n\n        public WebcamPage WebcamPage => ServiceProvider.Get<WebcamPage>();\n        \n        public MainViewModel MainViewModel => ServiceProvider.Get<MainViewModel>();\n\n        public RecentViewModel RecentViewModel => ServiceProvider.Get<RecentViewModel>();\n\n        public ScreenShotViewModel ScreenShotViewModel => ServiceProvider.Get<ScreenShotViewModel>();\n\n        public AboutViewModel AboutViewModel => ServiceProvider.Get<AboutViewModel>();\n\n        public RegionSelectorViewModel RegionSelectorViewModel => ServiceProvider.Get<RegionSelectorViewModel>();\n\n        public FFmpegDownloadViewModel FFmpegDownloadViewModel => ServiceProvider.Get<FFmpegDownloadViewModel>();\n\n        public FFmpegLogViewModel FFmpegLog => ServiceProvider.Get<FFmpegLogViewModel>();\n\n        public IFpsManager FpsManager => ServiceProvider.Get<IFpsManager>();\n\n        public FFmpegCodecsViewModel FFmpegCodecsViewModel => ServiceProvider.Get<FFmpegCodecsViewModel>();\n\n        public ProxySettingsViewModel ProxySettingsViewModel => ServiceProvider.Get<ProxySettingsViewModel>();\n\n        public LicensesViewModel LicensesViewModel => ServiceProvider.Get<LicensesViewModel>();\n\n        public CrashLogsViewModel CrashLogsViewModel => ServiceProvider.Get<CrashLogsViewModel>();\n\n        public FileNameFormatViewModel FileNameFormatViewModel => ServiceProvider.Get<FileNameFormatViewModel>();\n\n        public YouTubeUploaderViewModel YouTubeUploaderViewModel => ServiceProvider.Get<YouTubeUploaderViewModel>();\n\n        public SoundsViewModel SoundsViewModel => ServiceProvider.Get<SoundsViewModel>();\n\n        public KeymapViewModel Keymap => ServiceProvider.Get<KeymapViewModel>();\n\n        public EditorWriter EditorWriter => ServiceProvider.Get<EditorWriter>();\n\n        public HotkeysViewModel HotkeysViewModel => ServiceProvider.Get<HotkeysViewModel>();\n\n        public IIconSet Icons => ServiceProvider.Get<IIconSet>();\n\n        public UpdateCheckerViewModel UpdateCheckerViewModel => ServiceProvider.Get<UpdateCheckerViewModel>();\n\n        public CustomImageOverlaysViewModel CustomImageOverlays => ServiceProvider.Get<CustomImageOverlaysViewModel>();\n\n        public CustomOverlaysViewModel CustomOverlays => ServiceProvider.Get<CustomOverlaysViewModel>();\n\n        public CensorOverlaysViewModel CensorOverlays => ServiceProvider.Get<CensorOverlaysViewModel>();\n\n        public ViewConditionsModel ViewConditions => ServiceProvider.Get<ViewConditionsModel>();\n\n        public TimerModel TimerModel => ServiceProvider.Get<TimerModel>();\n\n        public AudioSourceViewModel AudioSource => ServiceProvider.Get<AudioSourceViewModel>();\n\n        public WebcamModel WebcamModel => ServiceProvider.Get<WebcamModel>();\n\n        public VideoWritersViewModel VideoWritersViewModel => ServiceProvider.Get<VideoWritersViewModel>();\n\n        public VideoSourcesViewModel VideoSourcesViewModel => ServiceProvider.Get<VideoSourcesViewModel>();\n\n        public RecordingViewModel RecordingViewModel => ServiceProvider.Get<RecordingViewModel>();\n    }\n}"
  },
  {
    "path": "src/Captura/Models/SingleInstanceManager.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Captura.Models\n{\n    public static class SingleInstanceManager\n    {\n        // ReSharper disable once NotAccessedField.Local\n        static Mutex _mutex;\n        // ReSharper disable once NotAccessedField.Local\n        static Task _task;\n\n        // Mutex allows us to know whether another instance is already open\n        const string MutexId = \"captura-mutex-304bae7c-e520-4bfe-a308-c99476062091\";\n\n        // EventWaitHandle allows us to communicate to a already running instance\n        const string EventWaitHandleId = \"captura-wait-304bae7c-e520-4bfe-a308-c99476062091\";\n\n        public static void SingleInstanceCheck()\n        {\n            _mutex = new Mutex(true, MutexId, out var createdNew);\n\n            if (!createdNew)\n            {\n                // Bring the already running instance to the foreground\n                var handle = CreateWaitHandle();\n                handle.Set();\n\n                // Exit duplicate instance\n                Environment.Exit(0);\n            }\n        }\n\n        static EventWaitHandle CreateWaitHandle()\n        {\n            return new EventWaitHandle(false, EventResetMode.AutoReset, EventWaitHandleId);\n        }\n\n        public static void StartListening(Action Callback)\n        {\n            // First instance listens for events from other instances in a loop\n            _task = Task.Run(() =>\n            {\n                var waitHandle = CreateWaitHandle();\n\n                while (true)\n                {\n                    waitHandle.WaitOne();\n\n                    // Callback should bring first instance to foreground\n                    Callback.Invoke();\n                }\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Models/SystemInfo.cs",
    "content": "﻿using System;\nusing System.Management;\nusing System.Text;\nusing Captura.Audio;\nusing Captura.ViewModels;\nusing Captura.Webcam;\n\nnamespace Captura.Models\n{\n    public static class SystemInfo\n    {\n        public static string GetInfo()\n        {\n            var sb = new StringBuilder();\n\n            sb.AppendLine($\"{nameof(Captura)} v{AboutViewModel.Version}\");\n            sb.AppendLine(OsInfo());\n            sb.AppendLine($\"{(Environment.Is64BitOperatingSystem ? 64 : 32)}-bit OS\");\n            sb.AppendLine($\"{(Environment.Is64BitProcess ? 64 : 32)}-bit Process\");\n            sb.AppendLine($\"{Environment.ProcessorCount} processor(s)\");\n\n            sb.AppendLine();\n            sb.Append(CpuInfo());\n            sb.Append(RamInfo());\n            sb.Append(GpuInfo());\n\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            try\n            {\n                sb.AppendLine($\"Desktop: {platformServices.DesktopRectangle}\");\n\n                foreach (var screen in platformServices.EnumerateScreens())\n                {\n                    sb.AppendLine($\"Screen: {screen.DeviceName}: {screen.Rectangle}\");\n                }\n            }\n            catch\n            {\n                sb.AppendLine(\"Unable to get screen dimensions\");\n            }\n\n            var audioSource = ServiceProvider.Get<IAudioSource>();\n\n            try\n            {\n                foreach (var mic in audioSource.Microphones)\n                {\n                    sb.AppendLine($\"Mic: {mic.Name}\");\n                }\n\n                foreach (var speaker in audioSource.Speakers)\n                {\n                    sb.AppendLine($\"Speaker: {speaker.Name}\");\n                }\n            }\n            catch\n            {\n                sb.AppendLine(\"Unable to get audio devices\");\n            }\n\n            try\n            {\n                var webcamSource = ServiceProvider.Get<IWebCamProvider>();\n\n                foreach (var webcam in webcamSource.GetSources())\n                {\n                    sb.AppendLine($\"Webcam: {webcam.Name}\");\n                }\n            }\n            catch\n            {\n                sb.AppendLine(\"Unable to get webcams\");\n            }\n\n            sb.AppendLine();\n\n            return sb.ToString();\n        }\n\n        static string DeviceInformation(string ClassName, string[] Properties)\n        {\n            var sb = new StringBuilder();\n\n            foreach (var instance in new ManagementClass(ClassName).GetInstances())\n            {\n                foreach (var property in Properties)\n                {\n                    try\n                    {\n                        sb.AppendLine($\"{property}: {instance.Properties[property].Value}\");\n                    }\n                    catch\n                    {\n                        //Add codes to manage more information\n                    }\n                }\n                sb.AppendLine();\n            }\n\n            return sb.ToString();\n        }\n\n        static string CpuInfo()\n        {\n            return DeviceInformation(\"Win32_Processor\", new[]\n            {\n                \"Name\",\n                \"NumberOfCores\",\n                \"NumberOfLogicalProcessors\"\n            });\n        }\n\n        static string GpuInfo()\n        {\n            return DeviceInformation(\"Win32_VideoController\", new[]\n            {\n                \"Name\",\n                \"AdapterRAM\"\n            });\n        }\n\n        static string OsInfo()\n        {\n            var devInfo = DeviceInformation(\"Win32_OperatingSystem\", new[]\n            {\n                \"Name\"\n            });\n\n            return $\"OS: {devInfo.Split(':')[1].Trim()}\";\n        }\n\n        static string RamInfo()\n        {\n            return DeviceInformation(\"Win32_PhysicalMemory\", new[]\n            {\n                \"Name\",\n                \"Capacity\"\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Models/SystemTray.cs",
    "content": "﻿using Hardcodet.Wpf.TaskbarNotification;\nusing System;\nusing System.Windows.Controls.Primitives;\nusing Captura.Audio;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class SystemTray : ISystemTray, IDisposable\n    {\n        bool _first = true;\n\n        /// <summary>\n        /// Using a Function ensures that the <see cref=\"TaskbarIcon\"/> object is used only after it is initialised.\n        /// </summary>\n        readonly Func<TaskbarIcon> _trayIcon;\n        readonly Settings _settings;\n        readonly IAudioPlayer _audioPlayer;\n\n        readonly NotificationStack _notificationStack = new NotificationStack();\n\n        public SystemTray(Func<TaskbarIcon> TaskbarIcon, Settings Settings, IAudioPlayer AudioPlayer)\n        {\n            _trayIcon = TaskbarIcon;\n            _settings = Settings;\n            _audioPlayer = AudioPlayer;\n\n            _notificationStack.Opacity = 0;\n        }\n\n        public void HideNotification()\n        {\n            _notificationStack.Hide();\n        }\n\n        void Show()\n        {\n            var trayIcon = _trayIcon.Invoke();\n\n            if (trayIcon != null && _first)\n            {\n                trayIcon.ShowCustomBalloon(_notificationStack, PopupAnimation.None, null);\n\n                _first = false;\n            }\n\n            _audioPlayer.Play(SoundKind.Notification);\n\n            _notificationStack.Show();\n        }\n\n        public void ShowScreenShotNotification(string FilePath)\n        {\n            if (!_settings.Tray.ShowNotifications)\n                return;\n\n            _notificationStack.Add(new ScreenShotBalloon(FilePath));\n\n            Show();\n        }\n\n        public void ShowNotification(INotification Notification)\n        {\n            if (!_settings.Tray.ShowNotifications)\n                return;\n\n            _notificationStack.Add(new NotificationBalloon(Notification));\n\n            Show();\n        }\n\n        public void Dispose()\n        {\n            _trayIcon.Invoke()?.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Models/VideoSourcePicker.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class VideoSourcePicker : IVideoSourcePicker\n    {\n        public IWindow PickWindow(Predicate<IWindow> Filter = null)\n        {\n            return VideoSourcePickerWindow.PickWindow(Filter);\n        }\n\n        public IScreen PickScreen()\n        {\n            return ScreenPickerWindow.PickScreen();\n        }\n\n        public Rectangle? PickRegion()\n        {\n            return RegionPickerWindow.PickRegion();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Pages/AboutPage.xaml",
    "content": "﻿<Page xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:sys=\"clr-namespace:System;assembly=mscorlib\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      x:Class=\"Captura.AboutPage\"\n      Title=\"{Binding About, Source={StaticResource Loc}, Mode=OneWay}\"\n      DataContext=\"{Binding AboutViewModel, Source={StaticResource ServiceLocator}}\">\n    <Grid>\n        <Grid.Resources>\n            <Style TargetType=\"Hyperlink\" BasedOn=\"{StaticResource {x:Type Hyperlink}}\">\n                <Setter Property=\"Command\" Value=\"{Binding HyperlinkCommand}\"/>\n            </Style>\n            <Style TargetType=\"captura:ModernButton\" BasedOn=\"{StaticResource IconButton}\"/>\n        </Grid.Resources>\n        <ScrollViewer>\n            <StackPanel MinWidth=\"150\"\n                        Margin=\"10\">\n                <DockPanel>\n                    <captura:StatusBar DockPanel.Dock=\"Bottom\"\n                                       Margin=\"7,3\"\n                                       Opacity=\"0.9\"/>\n\n                    <TextBlock TextWrapping=\"Wrap\"\n                               LineHeight=\"30\"\n                               Style=\"{StaticResource TextColor}\">\n                        <Run FontSize=\"20\" Text=\"Captura\"/> <Run Text=\"{Binding AppVersion, Mode=OneWay}\"/><LineBreak/>\n                        © <Run Text=\"{Binding Year, Source={x:Static sys:DateTime.Now}, Mode=OneWay}\"/> <Hyperlink CommandParameter=\"https://github.com/MathewSachin\">Mathew Sachin</Hyperlink>\n                    </TextBlock>\n                </DockPanel>\n\n                <WrapPanel HorizontalAlignment=\"Center\">\n                    <captura:ModernButton Content=\"GitHub\"\n                                          IconData=\"{Binding Icons.GitHub, Source={StaticResource ServiceLocator}}\"\n                                          Command=\"{Binding HyperlinkCommand}\"\n                                          CommandParameter=\"https://github.com/MathewSachin/Captura/\"/>\n\n                    <captura:ModernButton Content=\"{Binding Donate, Source={StaticResource Loc}, Mode=OneWay}\"\n                                          IconData=\"{Binding Icons.PayPal, Source={StaticResource ServiceLocator}}\"\n                                          Command=\"{Binding HyperlinkCommand}\"\n                                          CommandParameter=\"https://www.paypal.me/MathewSachin\"/>\n\n                    <captura:ModernButton Content=\"{Binding Website, Source={StaticResource Loc}, Mode=OneWay}\"\n                                          IconData=\"{Binding Icons.Web, Source={StaticResource ServiceLocator}}\"\n                                          Command=\"{Binding HyperlinkCommand}\"\n                                          CommandParameter=\"https://MathewSachin.github.io/Captura\"/>\n                </WrapPanel>\n\n                <GridSplitter Height=\"3\"\n                              IsEnabled=\"False\"\n                              Margin=\"0,10\"/>\n\n                <WrapPanel HorizontalAlignment=\"Center\">\n                    <captura:ModernButton Content=\"{Binding WantToTranslate, Source={StaticResource Loc}, Mode=OneWay}\"\n                                          IconData=\"{Binding Icons.Translate, Source={StaticResource ServiceLocator}}\"\n                                          Command=\"{Binding HyperlinkCommand}\"\n                                          CommandParameter=\"https://mathewsachin.github.io/Captura/translation\"/>\n\n                    <captura:ModernButton Content=\"{Binding Changelog, Source={StaticResource Loc}, Mode=OneWay}\"\n                                          IconData=\"{Binding Icons.History, Source={StaticResource ServiceLocator}}\"\n                                          Command=\"{Binding HyperlinkCommand}\"\n                                          CommandParameter=\"https://mathewsachin.github.io/Captura/changelog\"/>\n                </WrapPanel>\n\n                <WrapPanel HorizontalAlignment=\"Center\">\n                    <captura:ModernButton Content=\"{Binding ViewLicenses, Source={StaticResource Loc}, Mode=OneWay}\"\n                                          IconData=\"{Binding Icons.NewFile, Source={StaticResource ServiceLocator}}\"\n                                          Command=\"GoToPage\"\n                                          CommandParameter=\"/Pages/LicensesPage.xaml\"/>\n\n                    <captura:ModernButton Content=\"{Binding ViewCrashLogs, Source={StaticResource Loc}, Mode=OneWay}\"\n                                          IconData=\"{Binding Icons.Error, Source={StaticResource ServiceLocator}}\"\n                                          Command=\"GoToPage\"\n                                          CommandParameter=\"/Pages/CrashLogsPage.xaml\"/>\n                </WrapPanel>\n\n                <Label Margin=\"0,15,0,5\">\n                    <TextBlock Text=\"{Binding Tools, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                </Label>\n                \n                <WrapPanel Margin=\"3\">\n                    <Button ToolTip=\"{Binding Trim, Source={StaticResource Loc}, Mode=OneWay}\"\n                            Padding=\"5\"\n                            Margin=\"0,0,10,10\"\n                            Click=\"OpenAudioVideoTrimmer\">\n                        <Path Data=\"{Binding Icons.Trim, Source={StaticResource ServiceLocator}}\"\n                              Width=\"15\"\n                              Height=\"15\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              VerticalAlignment=\"Center\"/>\n                    </Button>\n\n                    <Button ToolTip=\"{Binding UploadToImgur, Source={StaticResource Loc}, Mode=OneWay}\"\n                            Padding=\"5\"\n                            Margin=\"0,0,10,10\"\n                            Click=\"UploadToImgur\">\n                        <Path Data=\"{Binding Icons.Upload, Source={StaticResource ServiceLocator}}\"\n                              Width=\"15\"\n                              Height=\"15\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              VerticalAlignment=\"Center\"/>\n                    </Button>\n                </WrapPanel>\n            </StackPanel>\n        </ScrollViewer>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/AboutPage.xaml.cs",
    "content": "﻿using System.Windows;\nusing Captura.Views;\nusing Microsoft.Win32;\n\nnamespace Captura\n{\n    public partial class AboutPage\n    {\n        void OpenAudioVideoTrimmer(object Sender, RoutedEventArgs E)\n        {\n            new TrimmerWindow().ShowAndFocus();\n        }\n\n        async void UploadToImgur(object Sender, RoutedEventArgs E)\n        {\n            var ofd = new OpenFileDialog\n            {\n                Filter = \"Image Files|*.png;*.jpg;*.jpeg;*.bmp;*.wmp;*.tiff\",\n                CheckFileExists = true,\n                CheckPathExists = true\n            };\n\n            if (ofd.ShowDialog().GetValueOrDefault())\n            {\n                var imgSystem = ServiceProvider.Get<IImagingSystem>();\n\n                using var img = imgSystem.LoadBitmap(ofd.FileName);\n                await img.UploadImage();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/AudioPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.AudioPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      Title=\"{Binding Audio, Source={StaticResource Loc}, Mode=OneWay}\">\n    <Grid Margin=\"5\">\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition/>\n            <ColumnDefinition Width=\"Auto\"/>\n            <ColumnDefinition/>\n        </Grid.ColumnDefinitions>\n        <StackPanel DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\"\n                    Margin=\"5,0,0,0\"\n                    IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n            <DockPanel Margin=\"0,0,0,10\">\n                <captura:ModernButton ToolTip=\"{Binding Refresh, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      Command=\"{Binding AudioSource.RefreshCommand, Source={StaticResource ServiceLocator}}\"\n                                      IconData=\"{Binding Icons.Refresh, Source={StaticResource ServiceLocator}}\"\n                                      DockPanel.Dock=\"Right\"/>\n\n                <TextBlock Text=\"{Binding AudioSource.Name, Source={StaticResource ServiceLocator}}\"\n                           Foreground=\"{DynamicResource Accent}\"\n                           DockPanel.Dock=\"Bottom\"/>\n            </DockPanel>\n\n            <CheckBox Content=\"Record Microphone\"\n                      IsChecked=\"{Binding Settings.Audio.RecordMicrophone, Mode=TwoWay}\"/>\n\n            <DockPanel Margin=\"10,5\">\n                <Path Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"5,0\"\n                      Stretch=\"Uniform\"\n                      VerticalAlignment=\"Center\"\n                      HorizontalAlignment=\"Center\"\n                      Data=\"{Binding Icons.Mic, Source={StaticResource ServiceLocator}}\"/>\n\n                <ComboBox IsEnabled=\"{Binding Settings.Audio.RecordMicrophone}\"\n                          ItemsSource=\"{Binding AudioSource.AvailableMicrophones, Source={StaticResource ServiceLocator}}\"\n                          SelectedValue=\"{Binding AudioSource.SelectedMicrophone, Source={StaticResource ServiceLocator}, Mode=TwoWay}\"/>\n            </DockPanel>\n\n            <ProgressBar Maximum=\"1\"\n                         Height=\"1\"\n                         Value=\"{Binding AudioSource.SelectedMicPeakLevel.Value, Source={StaticResource ServiceLocator}, Mode=OneWay}\"/>\n\n            <CheckBox Content=\"Record Speaker\"\n                      Margin=\"0,10,0,0\"\n                      IsChecked=\"{Binding Settings.Audio.RecordSpeaker, Mode=TwoWay}\"/>\n\n            <DockPanel Margin=\"10,5\">\n                <Path Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"5,0\"\n                      Stretch=\"Uniform\"\n                      VerticalAlignment=\"Center\"\n                      HorizontalAlignment=\"Center\"\n                      Data=\"{Binding Icons.Speaker, Source={StaticResource ServiceLocator}}\"/>\n\n                <ComboBox IsEnabled=\"{Binding Settings.Audio.RecordSpeaker}\"\n                          ItemsSource=\"{Binding AudioSource.AvailableSpeakers, Source={StaticResource ServiceLocator}}\"\n                          SelectedValue=\"{Binding AudioSource.SelectedSpeaker, Source={StaticResource ServiceLocator}, Mode=TwoWay}\"/>\n            </DockPanel>\n\n            <ProgressBar Maximum=\"1\"\n                         Height=\"1\"\n                         Value=\"{Binding AudioSource.SelectedSpeakerPeakLevel.Value, Source={StaticResource ServiceLocator}, Mode=OneWay}\"/>\n\n            <DockPanel Margin=\"0,10\">\n                <Label Content=\"{Binding Quality, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}:\"/>\n                <Label Content=\"{Binding Settings.Audio.Quality}\"\n                       ContentStringFormat=\"{}{0:N0}%\"\n                       Margin=\"5,0\"\n                       MinWidth=\"30\"\n                       HorizontalContentAlignment=\"Right\"/>\n                <Slider Minimum=\"1\" \n                        Maximum=\"100\"\n                        SelectionStart=\"70\"\n                        SelectionEnd=\"90\"\n                        IsSelectionRangeEnabled=\"True\"\n                        Value=\"{Binding Settings.Audio.Quality}\"/>\n            </DockPanel>\n\n            <StackPanel Margin=\"0,20,0,0\">\n                <CheckBox IsChecked=\"{Binding Settings.Audio.SeparateFilePerSource}\"\n                          Content=\"{Binding SeparateAudioFiles, Source={StaticResource Loc}, Mode=OneWay}\"\n                          Margin=\"0,5\"/>\n            </StackPanel>\n        </StackPanel>\n        <GridSplitter Grid.Column=\"1\"\n                      Width=\"1\"\n                      Margin=\"7,0\"/>\n        <DockPanel Grid.Column=\"2\">\n            <Label Margin=\"0,10\"\n                   Content=\"{Binding Sounds, Source={StaticResource Loc}, Mode=OneWay}\"\n                   FontWeight=\"Bold\"\n                   FontSize=\"15\"\n                   DockPanel.Dock=\"Top\"/>\n\n            <ScrollViewer>\n                <Frame Source=\"SoundsPage.xaml\"/>\n            </ScrollViewer>\n        </DockPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/AudioPage.xaml.cs",
    "content": "﻿using Captura.Models;\n\nnamespace Captura\n{\n    public partial class AudioPage\n    {\n        public AudioPage()\n        {\n            IsVisibleChanged += (S, E) =>\n            {\n                var audioSourceVm = ServiceProvider.Get<AudioSourceViewModel>();\n\n                audioSourceVm.ListeningPeakLevel = IsVisible;\n            };\n\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/CensorOverlaysPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.CensorOverlaysPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n      Title=\"Censor Overlays\">\n    <Grid>\n        <DockPanel DataContext=\"{Binding CensorOverlays, Source={StaticResource ServiceLocator}}\">\n            <DockPanel DockPanel.Dock=\"Top\">\n                <captura:ModernButton ToolTip=\"Add\"\n                                      Command=\"{Binding AddCommand}\"\n                                      IconData=\"{Binding Icons.Add, Source={StaticResource ServiceLocator}}\"/>\n                <Label Content=\"{Binding Add, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </DockPanel>\n\n            <ListView Margin=\"5\"\n                      ItemsSource=\"{Binding Collection}\"\n                      SelectedItem=\"{Binding SelectedItem, Mode=TwoWay}\">\n                <ListView.ItemTemplate>\n                    <DataTemplate>\n                        <TextBlock Text=\"Censor\"/>\n                    </DataTemplate>\n                </ListView.ItemTemplate>\n            </ListView>\n\n            <GridSplitter Width=\"1\"/>\n\n            <DockPanel Visibility=\"{Binding SelectedItem, Converter={StaticResource NotNullConverter}}\"\n                       Margin=\"10\"\n                       VerticalAlignment=\"Top\">\n                <Grid Margin=\"0,15,0,5\"\n                      DockPanel.Dock=\"Bottom\">\n                    <Grid.ColumnDefinitions>\n                        <ColumnDefinition Width=\"Auto\"/>\n                        <ColumnDefinition Width=\"*\"/>\n                        <ColumnDefinition Width=\"Auto\"/>\n                        <ColumnDefinition Width=\"*\"/>\n                    </Grid.ColumnDefinitions>\n\n                    <Label Content=\"Size\"\n                           Margin=\"0,0,5,0\"/>\n\n                    <xctk:IntegerUpDown Value=\"{Binding SelectedItem.Width, Mode=TwoWay}\"\n                                        Grid.Column=\"1\"\n                                        Minimum=\"1\"/>\n\n                    <Label Content=\"x\"\n                           Grid.Column=\"2\"\n                           Margin=\"5,0\"/>\n\n                    <xctk:IntegerUpDown Value=\"{Binding SelectedItem.Height, Mode=TwoWay}\"\n                                        Grid.Column=\"3\"\n                                        Minimum=\"1\"/>\n                </Grid>\n\n                <captura:PositionSettingsControl Margin=\"0,5\"\n                                                 DataContext=\"{Binding SelectedItem}\"\n                                                 DockPanel.Dock=\"Bottom\"/>\n\n                <DockPanel DockPanel.Dock=\"Top\">\n                    <captura:ModernButton ToolTip=\"Remove\"\n                                          Command=\"{Binding RemoveCommand}\"\n                                          CommandParameter=\"{Binding SelectedItem}\"\n                                          IconData=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"\n                                          DockPanel.Dock=\"Right\"/>\n\n                    <CheckBox IsChecked=\"{Binding SelectedItem.Display, Mode=TwoWay}\"\n                              Content=\"Display\"/>\n                </DockPanel>\n            </DockPanel>\n        </DockPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/CensorOverlaysPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class CensorOverlaysPage\n    {\n        public CensorOverlaysPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/CrashLogsPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.Views.CrashLogsPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:local=\"clr-namespace:Captura\"\n      Title=\"{Binding CrashLogs, Source={StaticResource Loc}, Mode=OneWay}\"\n      DataContext=\"{Binding CrashLogsViewModel, Source={StaticResource ServiceLocator}}\">\n    <Page.InputBindings>\n        <KeyBinding Key=\"C\"\n                    Modifiers=\"Control\"\n                    Command=\"{Binding CopyToClipboardCommand}\"/>\n    </Page.InputBindings>\n    <DockPanel>\n        <ListView ItemsSource=\"{Binding CrashLogs}\"\n                  SelectedValue=\"{Binding SelectedCrashLog, Mode=TwoWay}\"\n                  Width=\"160\"\n                  Padding=\"5,0\"\n                  BorderThickness=\"0,0,0.6,0\">\n            <ListView.ItemTemplate>\n                <DataTemplate>\n                    <TextBlock Text=\"{Binding Name, Mode=OneWay}\"/>\n                </DataTemplate>\n            </ListView.ItemTemplate>\n        </ListView>\n        <DockPanel DockPanel.Dock=\"Top\"\n                   Visibility=\"{Binding SelectedCrashLog, Converter={StaticResource NotNullConverter}}\"\n                   Margin=\"5\">\n            <local:ModernButton IconData=\"{Binding Icons.Delete, Source={StaticResource ServiceLocator}}\"\n                                DockPanel.Dock=\"Right\"\n                                Command=\"{Binding RemoveCommand}\"\n                                Foreground=\"#b71c1c\"\n                                ToolTip=\"{Binding Delete, Source={StaticResource Loc}, Mode=OneWay}\"/>\n\n            <Button Command=\"{Binding CopyToClipboardCommand}\"\n                    Margin=\"5\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.Clipboard, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"{Binding CopyToClipboard, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                </DockPanel>\n            </Button>\n        </DockPanel>\n\n        <Border DataContext=\"{Binding SelectedCrashLog}\"\n                Margin=\"10,5\">\n            <DockPanel>\n                <Label Margin=\"5\"\n                       DockPanel.Dock=\"Top\">\n                    <TextBlock Text=\"{Binding Name}\"\n                               Style=\"{StaticResource Heading1}\"/>\n                </Label>\n\n                <ScrollViewer HorizontalScrollBarVisibility=\"Auto\">\n                    <Label Margin=\"5\"\n                           VerticalContentAlignment=\"Top\"\n                           Content=\"{Binding Content}\"/>\n                </ScrollViewer>\n            </DockPanel>\n        </Border>\n    </DockPanel>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/CrashLogsPage.xaml.cs",
    "content": "﻿namespace Captura.Views\n{\n    public partial class CrashLogsPage\n    {\n        public CrashLogsPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/FFmpegCodecsPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.FFmpegCodecsPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:local=\"clr-namespace:Captura\"\n      xmlns:mui=\"http://firstfloorsoftware.com/ModernUI\"\n      xmlns:ffmpeg=\"clr-namespace:Captura.FFmpeg;assembly=Captura.FFmpeg\">\n    <Grid>\n        <TabControl Background=\"Transparent\"\n                    BorderThickness=\"0\">\n            <TabControl.ContentTemplate>\n                <DataTemplate>\n                    <DockPanel>\n                        <GridSplitter Height=\"1\"\n                                      Margin=\"0,2\"\n                                      IsEnabled=\"False\"\n                                      DockPanel.Dock=\"Top\"/>\n                        <mui:TransitioningContentControl Content=\"{Binding}\"/>\n                    </DockPanel>\n                </DataTemplate>\n            </TabControl.ContentTemplate>\n            <TabItem Header=\"x264\">\n                <Grid Margin=\"5\"\n                      DataContext=\"{Binding FFmpegCodecsViewModel, Source={StaticResource ServiceLocator}}\">\n                    <Grid.ColumnDefinitions>\n                        <ColumnDefinition Width=\"Auto\"/>\n                        <ColumnDefinition Width=\"*\"/>\n                    </Grid.ColumnDefinitions>\n                    <Grid.RowDefinitions>\n                        <RowDefinition Height=\"Auto\"/>\n                        <RowDefinition Height=\"Auto\"/>\n                        <RowDefinition Height=\"Auto\"/>\n                        <RowDefinition Height=\"Auto\"/>\n                    </Grid.RowDefinitions>\n                    \n                    <Label Content=\"Pixel Format\"\n                           ContentStringFormat=\"{}{0}: \"\n                           Margin=\"0,5,5,5\"/>\n                    \n                    <ComboBox Grid.Column=\"1\"\n                              ItemsSource=\"{x:Static ffmpeg:X264Settings.PixelFormats}\"\n                              SelectedValue=\"{Binding Settings.X264.PixelFormat, Mode=TwoWay}\"\n                              Margin=\"0,5\"/>\n\n                    <Label Content=\"yuv420p has wider support whereas yuv444p has better quality\"\n                           Grid.Row=\"1\"\n                           Grid.ColumnSpan=\"2\"\n                           FontWeight=\"Light\"\n                           Margin=\"0,0,0,5\"/>\n\n                    <Label Content=\"Preset\"\n                           ContentStringFormat=\"{}{0}: \"\n                           Grid.Row=\"2\"\n                           Margin=\"0,5,5,5\"/>\n\n                    <ComboBox Grid.Column=\"1\"\n                              Grid.Row=\"2\"\n                              ItemsSource=\"{x:Static ffmpeg:X264Settings.Presets}\"\n                              SelectedValue=\"{Binding Settings.X264.Preset, Mode=TwoWay}\"\n                              Margin=\"0,5\"/>\n\n                    <Label Content=\"ultrafast is recommended\"\n                           Grid.Row=\"3\"\n                           Grid.ColumnSpan=\"2\"\n                           FontWeight=\"Light\"/>\n                </Grid>\n            </TabItem>\n            <TabItem Header=\"Custom\">\n                <DockPanel DataContext=\"{Binding FFmpegCodecsViewModel, Source={StaticResource ServiceLocator}}\"\n                           Name=\"CustomCodecsPanel\">\n                    <DockPanel DockPanel.Dock=\"Top\">\n                        <local:ModernButton ToolTip=\"Add\"\n                                            Command=\"{Binding AddCustomCodecCommand}\"\n                                            IconData=\"{Binding Icons.Add, Source={StaticResource ServiceLocator}}\"/>\n                        \n                        <Label Content=\"Add Codec\"\n                               VerticalAlignment=\"Center\"/>\n                    </DockPanel>\n                    \n                    <Grid>\n                        <ItemsControl ItemsSource=\"{Binding Settings.CustomCodecs}\">\n                            <ItemsControl.ItemTemplate>\n                                <DataTemplate>\n                                    <Border Margin=\"5\"\n                                            BorderThickness=\"0.5\"\n                                            BorderBrush=\"{StaticResource ItemText}\">\n                                        <Grid Margin=\"5\">\n                                            <Grid.ColumnDefinitions>\n                                                <ColumnDefinition Width=\"Auto\"/>\n                                                <ColumnDefinition/>\n                                                <ColumnDefinition Width=\"Auto\"/>\n                                            </Grid.ColumnDefinitions>\n                                    \n                                            <Grid.RowDefinitions>\n                                                <RowDefinition/>\n                                                <RowDefinition/>\n                                                <RowDefinition/>\n                                                <RowDefinition/>\n                                            </Grid.RowDefinitions>\n\n                                            <local:ModernButton ToolTip=\"Delete\"\n                                                                Grid.Column=\"2\"\n                                                                CommandParameter=\"{Binding}\"\n                                                                Command=\"{Binding DataContext.RemoveCustomCodecCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}\"\n                                                                IconData=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"/>\n                                    \n                                            <Label Content=\"Name\"/>\n                                            \n                                            <TextBox Text=\"{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"\n                                                     Grid.Column=\"1\"\n                                                     Margin=\"5\"/>\n                                            \n                                            <Label Content=\"Args\"\n                                                   Grid.Row=\"1\"/>\n\n                                            <TextBox Text=\"{Binding Args, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"\n                                                     Grid.Column=\"1\"\n                                                     Grid.Row=\"1\"\n                                                     Margin=\"5\"/>\n\n                                            <Label Content=\"Extension\"\n                                                   Grid.Row=\"2\"/>\n\n                                            <TextBox Text=\"{Binding Extension, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"\n                                                     Grid.Column=\"1\"\n                                                     Grid.Row=\"2\"\n                                                     Margin=\"5\"/>\n                                            \n                                            <Label Content=\"Audio Format\"\n                                                   Grid.Row=\"3\"/>\n                                            \n                                            <ComboBox ItemsSource=\"{Binding DataContext.AudioCodecNames, ElementName=CustomCodecsPanel}\"\n                                                      SelectedValue=\"{Binding AudioFormat, Mode=TwoWay}\"\n                                                      Grid.Row=\"3\"\n                                                      Grid.Column=\"1\"\n                                                      Margin=\"5\"/>\n                                        </Grid>\n                                    </Border>\n                                </DataTemplate>\n                            </ItemsControl.ItemTemplate>\n                        </ItemsControl>\n                    </Grid>\n                </DockPanel>\n            </TabItem>\n        </TabControl>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/FFmpegCodecsPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class FFmpegCodecsPage\n    {\n        public FFmpegCodecsPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/FFmpegLogsPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.FFmpegLogsPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:local=\"clr-namespace:Captura\"\n      Title=\"{Binding FFmpegLog, Source={StaticResource Loc}, Mode=OneWay}\"\n      DataContext=\"{Binding FFmpegLog, Source={StaticResource ServiceLocator}}\">\n    <DockPanel Margin=\"5\">\n        <ListView ItemsSource=\"{Binding LogItems}\"\n                  SelectedItem=\"{Binding SelectedLogItem, Mode=TwoWay}\"\n                  Width=\"200\"\n                  Padding=\"5,0\"\n                  BorderThickness=\"0,0,0.6,0\">\n            <ListView.ItemTemplate>\n                <DataTemplate>\n                    <TextBlock Text=\"{Binding Name, Mode=OneWay}\"/>\n                </DataTemplate>\n            </ListView.ItemTemplate>\n        </ListView>\n\n        <DockPanel Visibility=\"{Binding SelectedLogItem, Converter={StaticResource NotNullConverter}}\"\n                   Margin=\"5\">\n            <DockPanel.InputBindings>\n                <KeyBinding Key=\"C\"\n                            Modifiers=\"Control\"\n                            Command=\"{Binding CopyToClipboardCommand}\"/>\n                <KeyBinding Key=\"Delete\"\n                            Command=\"{Binding RemoveCommand}\"/>\n            </DockPanel.InputBindings>\n            <DockPanel DockPanel.Dock=\"Top\">\n                <local:ModernButton IconData=\"{Binding Icons.Delete, Source={StaticResource ServiceLocator}}\"\n                                    DockPanel.Dock=\"Right\"\n                                    Command=\"{Binding RemoveCommand}\"\n                                    Foreground=\"#b71c1c\"/>\n                \n                <Button Command=\"{Binding CopyToClipboardCommand}\"\n                        Margin=\"5\">\n                    <DockPanel>\n                        <Path Data=\"{Binding Icons.Clipboard, Source={StaticResource ServiceLocator}}\"\n                              Width=\"15\"\n                              Height=\"15\"\n                              Margin=\"0,0,10,0\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              VerticalAlignment=\"Center\"/>\n\n                        <TextBlock Text=\"{Binding CopyToClipboard, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                    </DockPanel>\n                </Button>\n            </DockPanel>\n\n            <Label Content=\"{Binding SelectedLogItem.Frame}\"\n                   DockPanel.Dock=\"Bottom\"/>\n\n            <StackPanel DockPanel.Dock=\"Top\">\n                <Label Content=\"Args\"\n                       FontWeight=\"Bold\"/>\n                <ScrollViewer Margin=\"0,0,0,10\"\n                              HorizontalScrollBarVisibility=\"Auto\">\n                    <Label Content=\"{Binding SelectedLogItem.Args}\"\n                           Margin=\"0,0,0,10\"/>\n                </ScrollViewer>\n\n                <Label Content=\"Output\"\n                       FontWeight=\"Bold\"/>\n            </StackPanel>\n\n            <ScrollViewer HorizontalScrollBarVisibility=\"Auto\">\n                <TextBlock Text=\"{Binding SelectedLogItem.Content, Mode=OneWay}\"\n                           Style=\"{StaticResource TextColor}\"/>\n            </ScrollViewer>\n        </DockPanel>\n    </DockPanel>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/FFmpegLogsPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class FFmpegLogsPage\n    {\n        public FFmpegLogsPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/FFmpegPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.FFmpegPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\"\n      Title=\"FFmpeg\">\n    <Grid Margin=\"5\">\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition/>\n            <ColumnDefinition Width=\"Auto\"/>\n            <ColumnDefinition/>\n        </Grid.ColumnDefinitions>\n        <StackPanel Margin=\"5\">\n            <Button Command=\"GoToPage\"\n                    CommandParameter=\"/Pages/FFmpegLogsPage.xaml\"\n                    Margin=\"0,5\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.History, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"{Binding FFmpegLog, Source={StaticResource Loc}, Mode=OneWay, StringFormat='{}{0} ...'}\"/>\n                </DockPanel>\n            </Button>\n\n            <Button IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                    Click=\"FFmpegDownload\"\n                    Margin=\"0,5\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.Download, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"{Binding DownloadFFmpeg, Source={StaticResource Loc}, Mode=OneWay, StringFormat='{}{0} ...'}\"/>\n                </DockPanel>\n            </Button>\n\n            <Label Content=\"{Binding FFmpegFolder, Source={StaticResource Loc}, Mode=OneWay}\"\n                   Margin=\"0,10,0,0\"\n                   FontWeight=\"Bold\"/>\n\n            <DockPanel Margin=\"0,5\">\n                <Button DockPanel.Dock=\"Right\"\n                        ToolTip=\"{Binding SelectFFmpegFolder, Source={StaticResource Loc}, Mode=OneWay}\"\n                        Command=\"{Binding SelectFFmpegFolderCommand}\"\n                        IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n                    <Path Stretch=\"UniformToFill\"\n                          Height=\"4\"\n                          Width=\"16\"\n                          Data=\"{Binding Icons.More, Source={StaticResource ServiceLocator}}\"/>\n                </Button>\n                <Button DockPanel.Dock=\"Right\"\n                        ToolTip=\"{Binding Reset, Source={StaticResource Loc}, Mode=OneWay}\"\n                        Command=\"{Binding ResetFFmpegFolderCommand}\"\n                        IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                        VerticalContentAlignment=\"Center\">\n                    <Path Stretch=\"UniformToFill\"\n                          Height=\"10\"\n                          Width=\"9\"\n                          Data=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"/>\n                </Button>\n\n                <Path Data=\"{Binding Icons.Folder, Source={StaticResource ServiceLocator}}\"\n                      Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"0,0,10,0\"\n                      Stretch=\"Uniform\"\n                      HorizontalAlignment=\"Center\"\n                      VerticalAlignment=\"Center\"/>\n\n                <Border ToolTip=\"{Binding Settings.FFmpeg.FolderPath}\"\n                        MouseUp=\"SelectFFmpegFolder\">\n                    <xctk:WatermarkTextBox IsReadOnly=\"True\"\n                                           IsEnabled=\"False\"\n                                           Watermark=\"Load From PATH or App Directory\"\n                                           Text=\"{Binding Settings.FFmpeg.FolderPath}\"/>\n                </Border>\n            </DockPanel>\n\n            <Label Margin=\"0,10,0,3\"\n                   Content=\"{Binding CustomSize, Source={StaticResource Loc}, Mode=OneWay}\"\n                   FontWeight=\"Bold\"/>\n\n            <Grid Margin=\"0,5\">\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"*\"/>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"*\"/>\n                </Grid.ColumnDefinitions>\n\n                <CheckBox Content=\"{Binding Resize, Source={StaticResource Loc}, Mode=OneWay}\"\n                          IsChecked=\"{Binding Settings.FFmpeg.Resize}\"\n                          Margin=\"0,0,5,0\"/>\n\n                <xctk:IntegerUpDown Value=\"{Binding Settings.FFmpeg.ResizeWidth}\"\n                                    Grid.Column=\"1\"\n                                    Minimum=\"2\"\n                                    IsEnabled=\"{Binding Settings.FFmpeg.Resize}\"/>\n\n                <Label Content=\"x\"\n                       Grid.Column=\"2\"\n                       Margin=\"5,0\"/>\n\n                <xctk:IntegerUpDown Value=\"{Binding Settings.FFmpeg.ResizeHeight}\"\n                                    Grid.Column=\"3\"\n                                    Minimum=\"2\"\n                                    IsEnabled=\"{Binding Settings.FFmpeg.Resize}\"/>\n            </Grid>\n\n            <Label Margin=\"0,10,0,0\"\n                   Content=\"{Binding StreamingKeys, Source={StaticResource Loc}, Mode=OneWay}\"\n                   FontWeight=\"Bold\"\n                   FontSize=\"15\"/>\n\n            <Grid Margin=\"0,5\">\n                <Grid.RowDefinitions>\n                    <RowDefinition/>\n                    <RowDefinition/>\n                    <RowDefinition/>\n                </Grid.RowDefinitions>\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"*\" MinWidth=\"200\"/>\n                </Grid.ColumnDefinitions>\n\n                <Path Data=\"{Binding Icons.Twitch, Source={StaticResource ServiceLocator}}\"\n                      Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"0,0,10,0\"\n                      Stretch=\"Uniform\"\n                      HorizontalAlignment=\"Center\"\n                      VerticalAlignment=\"Center\"/>\n                <Label Content=\"Twitch\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Grid.Column=\"1\"/>\n                <captura:ModernPasswordBox Grid.Column=\"2\"\n                                           Margin=\"2\"\n                                           Password=\"{Binding Settings.FFmpeg.TwitchKey}\"/>\n\n                <Path Data=\"{Binding Icons.YouTube, Source={StaticResource ServiceLocator}}\"\n                      Grid.Row=\"1\"\n                      Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"0,0,10,0\"\n                      Stretch=\"Uniform\"\n                      HorizontalAlignment=\"Center\"\n                      VerticalAlignment=\"Center\"/>\n                <Label Content=\"YouTube Live\"\n                       Grid.Row=\"1\"\n                       Grid.Column=\"1\"\n                       ContentStringFormat=\"{}{0}: \"/>\n                <captura:ModernPasswordBox Grid.Column=\"2\"\n                                           Grid.Row=\"1\"\n                                           Margin=\"2\"\n                                           Password=\"{Binding Settings.FFmpeg.YouTubeLiveKey}\"/>\n\n                <Path Data=\"{Binding Icons.Web, Source={StaticResource ServiceLocator}}\"\n                      Grid.Row=\"2\"\n                      Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"0,0,10,0\"\n                      Stretch=\"Uniform\"\n                      HorizontalAlignment=\"Center\"\n                      VerticalAlignment=\"Center\"/>\n                <Label Content=\"{Binding CustomUrl, Source={StaticResource Loc}, Mode=OneWay}\"\n                       Grid.Column=\"1\"\n                       Grid.Row=\"2\"\n                       ContentStringFormat=\"{}{0}:\"/>\n                <TextBox Grid.Row=\"2\"\n                         Grid.Column=\"2\"\n                         Margin=\"2\"\n                         Text=\"{Binding Settings.FFmpeg.CustomStreamingUrl}\"/>\n            </Grid>\n        </StackPanel>\n        <GridSplitter Grid.Column=\"1\"\n                      Width=\"1\"\n                      Margin=\"7,0\"/>\n        <DockPanel Grid.Column=\"2\">\n            <Label Margin=\"0,10\"\n                   Content=\"{Binding ConfigCodecs, Source={StaticResource Loc}, Mode=OneWay}\"\n                   FontWeight=\"Bold\"\n                   FontSize=\"15\"\n                   DockPanel.Dock=\"Top\"/>\n\n            <ScrollViewer>\n                <Frame Source=\"FFmpegCodecsPage.xaml\"/>\n            </ScrollViewer>\n        </DockPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/FFmpegPage.xaml.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Input;\nusing Captura.ViewModels;\nusing Captura.Views;\n\nnamespace Captura\n{\n    public partial class FFmpegPage\n    {\n        void FFmpegDownload(object Sender, RoutedEventArgs E)\n        {\n            FFmpegDownloaderWindow.ShowInstance();\n        }\n\n        void SelectFFmpegFolder(object Sender, MouseButtonEventArgs E)\n        {\n            if (DataContext is MainViewModel vm)\n            {\n                vm.SelectFFmpegFolderCommand.ExecuteIfCan();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/FileNameFormatPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.FileNameFormatPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      DataContext=\"{Binding FileNameFormatViewModel, Source={StaticResource ServiceLocator}}\"\n      Title=\"{Binding FileNaming, Source={StaticResource Loc}, Mode=OneWay}\">\n    <Grid>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition Width=\"9*\"/>\n            <ColumnDefinition Width=\"Auto\"/>\n            <ColumnDefinition Width=\"4*\"/>\n        </Grid.ColumnDefinitions>\n        <StackPanel Margin=\"5\">\n            <Label Content=\"File Name Format\"\n                   ContentStringFormat=\"{}{0}:\"\n                   FontWeight=\"Bold\"/>\n\n            <TextBox Margin=\"0,2\"\n                     Text=\"{Binding FilenameFormat, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"/>\n\n            <Label Content=\"Use '/' or '\\' to specify folders\"\n                   FontWeight=\"Thin\"\n                   Margin=\"0,0,0,10\"\n                   HorizontalAlignment=\"Right\"/>\n\n            <Label Content=\"File Name Preview\"\n                   ContentStringFormat=\"{}{0}:\"\n                   FontWeight=\"Bold\"/>\n\n            <Label Margin=\"0,2,0,10\"\n                   Content=\"{Binding FilenamePreview}\"/>\n\n            <captura:OutputFolderControl/>\n        </StackPanel>\n        <GridSplitter Grid.Column=\"1\"\n                      Width=\"1\"\n                      Margin=\"7,0\"/>\n        <ScrollViewer Grid.Column=\"2\">\n            <ItemsControl ItemsSource=\"{Binding FormatGroups}\">\n                <ItemsControl.ItemTemplate>\n                    <DataTemplate>\n                        <StackPanel Margin=\"5\">\n                            <Label Content=\"{Binding Name}\"\n                                   FontWeight=\"Bold\"\n                                   Margin=\"0,5,0,2\"/>\n\n                            <ItemsControl ItemsSource=\"{Binding Formats}\"\n                                          Grid.IsSharedSizeScope=\"True\">\n                                <ItemsControl.ItemTemplate>\n                                    <DataTemplate>\n                                        <Grid>\n                                            <Grid.ColumnDefinitions>\n                                                <ColumnDefinition Width=\"Auto\" SharedSizeGroup=\"FormatName\"/>\n                                                <ColumnDefinition Width=\"10\"/>\n                                                <ColumnDefinition/>\n                                            </Grid.ColumnDefinitions>\n\n                                            <Label Content=\"{Binding Format}\"\n                                                   FontWeight=\"DemiBold\"/>\n\n                                            <Label Content=\"{Binding Description}\"\n                                                   Grid.Column=\"2\"/>\n                                        </Grid>\n                                    </DataTemplate>\n                                </ItemsControl.ItemTemplate>\n                            </ItemsControl>\n                        </StackPanel>\n                    </DataTemplate>\n                </ItemsControl.ItemTemplate>\n            </ItemsControl>\n        </ScrollViewer>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/FileNameFormatPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class FileNameFormatPage\n    {\n        public FileNameFormatPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/HomePage.xaml",
    "content": "﻿<Page x:Class=\"Captura.HomePage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\">\n    <Grid>\n        <Grid.Resources>\n            <Style TargetType=\"Path\" x:Key=\"VideoSourceIcon\" BasedOn=\"{StaticResource {x:Type Path}}\">\n                <Setter Property=\"Width\" Value=\"20\"/>\n                <Setter Property=\"Height\" Value=\"20\"/>\n                <Setter Property=\"Margin\" Value=\"5\"/>\n                <Setter Property=\"Stretch\" Value=\"Uniform\"/>\n                <Setter Property=\"HorizontalAlignment\" Value=\"Center\"/>\n                <Setter Property=\"VerticalAlignment\" Value=\"Center\"/>\n                <Setter Property=\"Fill\" Value=\"{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=ContentControl}}\"/>\n            </Style>\n        </Grid.Resources>\n        <StackPanel Margin=\"5,0\">\n            <DockPanel Margin=\"0,-10,0,15\">\n                <ComboBox ItemsSource=\"{Binding WebcamModel.AvailableCams, Source={StaticResource ServiceLocator}}\"\n                          SelectedItem=\"{Binding WebcamModel.SelectedCam, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                          IsEnabled=\"{Binding ViewConditions.CanChangeWebcam.Value, Source={StaticResource ServiceLocator}}\"\n                          DisplayMemberPath=\"Name\"\n                          DockPanel.Dock=\"Right\"\n                          Margin=\"5,0,0,0\"\n                          Width=\"250\"\n                          Visibility=\"{Binding ViewConditions.IsWebcamMode.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\"/>\n\n                <Border BorderThickness=\"0.5\"\n                        BorderBrush=\"{DynamicResource ModernButtonBorder}\"\n                        Padding=\"5,2\">\n                    <StackPanel Orientation=\"Horizontal\">\n                        <Label Content=\"{Binding Settings.Video.RecorderMode}\"\n                               Foreground=\"{DynamicResource Accent}\"\n                               ContentStringFormat=\"{}{0}: \"/>\n                        <Label Content=\"{Binding VideoSourcesViewModel.SelectedVideoSourceKind.Name, Source={StaticResource ServiceLocator}}\"/>\n                        <Label Content=\"-\"\n                               Visibility=\"{Binding VideoSourcesViewModel.SelectedVideoSourceKind.Source.Name, Source={StaticResource ServiceLocator}, Converter={StaticResource NotNullConverter}}\"\n                               Margin=\"5,0\"/>\n                        <Label Content=\"{Binding VideoSourcesViewModel.SelectedVideoSourceKind.Source.Name, Source={StaticResource ServiceLocator}, TargetNullValue='No Source Selected', FallbackValue='No Source Selected'}\"\n                               Visibility=\"{Binding VideoSourcesViewModel.SelectedVideoSourceKind.Source.Name, Source={StaticResource ServiceLocator}, Converter={StaticResource NotNullConverter}}\"/>\n                    </StackPanel>\n                </Border>\n            </DockPanel>\n\n            <DockPanel Visibility=\"{Binding ViewConditions.IsRegionMode.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\">\n                <DockPanel DockPanel.Dock=\"Right\">\n                    <DockPanel DockPanel.Dock=\"Top\">\n                        <captura:ModernButton ToolTip=\"Clear all drawings\"\n                                              Foreground=\"#ff3330\"\n                                              IconData=\"{Binding Icons.Delete, Source={StaticResource ServiceLocator}}\"\n                                              DockPanel.Dock=\"Right\"\n                                              Command=\"{Binding RegionSelectorViewModel.ClearAllDrawingsCommand, Source={StaticResource ServiceLocator}}\"\n                                              Margin=\"-5\">\n                            <captura:ModernButton.LayoutTransform>\n                                <ScaleTransform ScaleX=\"0.8\" ScaleY=\"0.8\"/>\n                            </captura:ModernButton.LayoutTransform>\n                        </captura:ModernButton>\n                        <ListBox SelectedValuePath=\"Key\"\n                                 HorizontalContentAlignment=\"Center\"\n                                 HorizontalAlignment=\"Right\"\n                                 ItemsSource=\"{Binding RegionSelectorViewModel.Tools, Source={StaticResource ServiceLocator}}\"\n                                 SelectedValue=\"{Binding RegionSelectorViewModel.SelectedTool.Value, Mode=TwoWay, Source={StaticResource ServiceLocator}}\">\n                            <ListBox.ItemTemplate>\n                                <DataTemplate>\n                                    <Path Data=\"{Binding Key, Converter={StaticResource InkToolToIconConverter}}\"\n                                          Width=\"12\"\n                                          Height=\"12\"\n                                          Stretch=\"Uniform\"\n                                          HorizontalAlignment=\"Center\"\n                                          VerticalAlignment=\"Center\"\n                                          ToolTip=\"{Binding Value}\"\n                                          Fill=\"{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType=ContentControl}}\"\n                                          Margin=\"5,3\"/>\n                                </DataTemplate>\n                            </ListBox.ItemTemplate>\n                            <ListBox.ItemsPanel>\n                                <ItemsPanelTemplate>\n                                    <StackPanel Orientation=\"Horizontal\"/>\n                                </ItemsPanelTemplate>\n                            </ListBox.ItemsPanel>\n                        </ListBox>\n                    </DockPanel>\n\n                    <xctk:ColorPicker Margin=\"0,2,5,0\"\n                                      SelectedColor=\"{Binding RegionSelectorViewModel.BrushColor.Value, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                                      VerticalAlignment=\"Center\"\n                                      ColorMode=\"ColorCanvas\"\n                                      ShowAdvancedButton=\"True\"\n                                      AdvancedButtonHeader=\"Color Canvas\"\n                                      StandardButtonHeader=\"Pallette\"\n                                      Width=\"50\"\n                                      ShowRecentColors=\"True\"/>\n\n                    <xctk:IntegerUpDown Minimum=\"1\"\n                                        Maximum=\"99\"\n                                        Margin=\"0,2,0,0\"\n                                        Value=\"{Binding RegionSelectorViewModel.BrushSize.Value, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                                        VerticalAlignment=\"Center\"\n                                        DockPanel.Dock=\"Right\"/>\n                </DockPanel>\n\n                <GridSplitter Width=\"1\"\n                              Margin=\"5,0\"\n                              DockPanel.Dock=\"Right\"\n                              IsEnabled=\"False\"/>\n\n                <Grid>\n                    <Grid.ColumnDefinitions>\n                        <ColumnDefinition Width=\"Auto\"/>\n                        <ColumnDefinition/>\n                        <ColumnDefinition Width=\"Auto\"/>\n                        <ColumnDefinition/>\n                    </Grid.ColumnDefinitions>\n                    <Grid.RowDefinitions>\n                        <RowDefinition/>\n                        <RowDefinition/>\n                    </Grid.RowDefinitions>\n\n                    <Label Content=\"X:\"\n                           Margin=\"0,0,3,0\"/>\n                    <xctk:IntegerUpDown Grid.Column=\"1\"\n                                        Minimum=\"{x:Null}\"\n                                        VerticalAlignment=\"Center\"\n                                        Value=\"{Binding RegionSelectorViewModel.Left, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"/>\n\n                    <Label Content=\"Y:\"\n                           Grid.Column=\"2\"\n                           Margin=\"5,0,3,0\"/>\n                    <xctk:IntegerUpDown Grid.Column=\"3\"\n                                        Minimum=\"{x:Null}\"\n                                        VerticalAlignment=\"Center\"\n                                        Value=\"{Binding RegionSelectorViewModel.Top, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"/>\n\n                    <Label Content=\"W:\"\n                           Grid.Row=\"1\"\n                           Grid.Column=\"0\"\n                           Margin=\"0,0,3,0\"/>\n                    <xctk:IntegerUpDown Grid.Column=\"1\"\n                                        Grid.Row=\"1\"\n                                        VerticalAlignment=\"Center\"\n                                        Value=\"{Binding RegionSelectorViewModel.Width, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                                        IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"/>\n\n                    <Label Content=\"H:\"\n                           Grid.Column=\"2\"\n                           Grid.Row=\"1\"\n                           Margin=\"5,0,3,0\"/>\n                    <xctk:IntegerUpDown Grid.Column=\"3\"\n                                        Grid.Row=\"1\"\n                                        VerticalAlignment=\"Center\"\n                                        Value=\"{Binding RegionSelectorViewModel.Height, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                                        IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"/>\n                </Grid>\n            </DockPanel>\n\n            <DockPanel Margin=\"0,5\"\n                       Visibility=\"{Binding ViewConditions.IsAudioMode.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\">\n                <Label Content=\"{Binding AudioFormat, Source={StaticResource Loc}, Mode=OneWay}\"\n                       Margin=\"0,0,5,0\"/>\n\n                <ComboBox ItemsSource=\"{Binding VideoSourcesViewModel.NoVideoSourceProvider.Sources, Source={StaticResource ServiceLocator}}\"\n                          SelectedValue=\"{Binding VideoSourcesViewModel.NoVideoSourceProvider.SelectedSource, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                          IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"/>\n            </DockPanel>\n\n            <Grid Visibility=\"{Binding ViewConditions.IsAroundMouseMode.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\"\n                  Margin=\"0,0,0,5\">\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition/>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition/>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition/>\n                </Grid.ColumnDefinitions>\n\n                <Label Content=\"Width:\"\n                       Margin=\"5,0,3,0\"/>\n                <xctk:IntegerUpDown Grid.Column=\"1\"\n                                    Value=\"{Binding MainViewModel.Settings.AroundMouse.Width, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                                    IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"/>\n\n                <Label Content=\"Height:\"\n                       Grid.Column=\"2\"\n                       Margin=\"5,0,3,0\"/>\n                <xctk:IntegerUpDown Grid.Column=\"3\"\n                                    Value=\"{Binding MainViewModel.Settings.AroundMouse.Height, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                                    IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"/>\n\n                <Label Content=\"Margin:\"\n                       Grid.Column=\"4\"\n                       Margin=\"5,0,3,0\"/>\n                <xctk:IntegerUpDown Grid.Column=\"5\"\n                                    Value=\"{Binding MainViewModel.Settings.AroundMouse.Margin, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                                    IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"/>\n            </Grid>\n        </StackPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/HomePage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class HomePage\n    {\n        public HomePage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/HotkeysPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.Views.HotkeysPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:local=\"clr-namespace:Captura\"\n      xmlns:hotkeys=\"clr-namespace:Captura.Hotkeys;assembly=Captura.Hotkeys\"\n      DataContext=\"{Binding HotkeysViewModel, Source={StaticResource ServiceLocator}}\"\n      Title=\"{Binding Hotkeys, Source={StaticResource Loc}, Mode=OneWay}\">\n    <Grid>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition Width=\"4*\"/>\n            <ColumnDefinition Width=\"Auto\"/>\n            <ColumnDefinition Width=\"2*\"/>\n        </Grid.ColumnDefinitions>\n        <DockPanel Margin=\"5\">\n            <Grid DockPanel.Dock=\"Top\">\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition/>\n                    <ColumnDefinition/>\n                </Grid.ColumnDefinitions>\n\n                <Button Command=\"{Binding AddCommand}\"\n                        Margin=\"5\">\n                    <DockPanel>\n                        <Path Data=\"{Binding Icons.Plus, Source={StaticResource ServiceLocator}}\"\n                              Width=\"15\"\n                              Height=\"15\"\n                              Margin=\"0,0,10,0\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              VerticalAlignment=\"Center\"/>\n\n                        <TextBlock Text=\"{Binding Add, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                    </DockPanel>\n                </Button>\n                \n                <Button Grid.Column=\"1\"\n                        Command=\"{Binding ResetCommand}\"\n                        Margin=\"5\">\n                    <DockPanel>\n                        <Path Data=\"{Binding Icons.Restore, Source={StaticResource ServiceLocator}}\"\n                              Width=\"15\"\n                              Height=\"15\"\n                              Margin=\"0,0,10,0\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              VerticalAlignment=\"Center\"/>\n\n                        <TextBlock Text=\"{Binding RestoreDefaults, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                    </DockPanel>\n                </Button>\n            </Grid>\n            \n            <ScrollViewer Margin=\"0,5\">\n                <ItemsControl Margin=\"5\"\n                              ItemsSource=\"{Binding Hotkeys}\">\n                    <ItemsControl.Resources>\n                        <Style TargetType=\"local:HotkeySelector\" BasedOn=\"{StaticResource {x:Type Button}}\"/>\n                    </ItemsControl.Resources>\n                    <ItemsControl.ItemTemplate>\n                        <DataTemplate>\n                            <DockPanel>\n                                <GridSplitter Height=\"1\"\n                                              Margin=\"0,10\"\n                                              IsEnabled=\"False\"\n                                              DockPanel.Dock=\"Top\"/>\n                                \n                                <local:ModernButton DockPanel.Dock=\"Right\"\n                                                    CommandParameter=\"{Binding}\"\n                                                    IconData=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"\n                                                    Command=\"{Binding HotkeysViewModel.RemoveCommand, Source={StaticResource ServiceLocator}}\">\n                                    <local:ModernButton.LayoutTransform>\n                                        <ScaleTransform ScaleX=\"0.8\" ScaleY=\"0.8\"/>\n                                    </local:ModernButton.LayoutTransform>\n                                </local:ModernButton>\n                                \n                                <local:HotkeySelector IsEnabled=\"{Binding IsActive}\"\n                                                      HotkeyModel=\"{Binding}\"\n                                                      Width=\"200\"\n                                                      Margin=\"0,0,5,0\"\n                                                      DockPanel.Dock=\"Right\"/>\n\n                                <CheckBox IsChecked=\"{Binding IsActive, Mode=TwoWay}\"/>\n\n                                <ComboBox SelectedValue=\"{Binding Service, Mode=TwoWay}\"\n                                          DisplayMemberPath=\"Description\"\n                                          ItemsSource=\"{x:Static hotkeys:HotKeyManager.AllServices}\"\n                                          Margin=\"10,0\"\n                                          IsEnabled=\"{Binding IsActive}\"/>\n                            </DockPanel>\n                        </DataTemplate>\n                    </ItemsControl.ItemTemplate>\n                </ItemsControl>\n            </ScrollViewer>\n        </DockPanel>\n        <GridSplitter Grid.Column=\"1\"\n                      Width=\"1\"\n                      Margin=\"7,0\"/>\n        <StackPanel Margin=\"5\"\n                    Grid.Column=\"2\">\n            <Label Content=\"Toggle Region Picker\"\n                   FontWeight=\"Bold\"\n                   Margin=\"0,5\"/>\n\n            <CheckBox IsChecked=\"{Binding AboutViewModel.Settings.RegionPickerHotkeyAutoStartRecording, Source={StaticResource ServiceLocator}}\"\n                      Content=\"Automatically start recording\"/>\n        </StackPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/HotkeysPage.xaml.cs",
    "content": "﻿namespace Captura.Views\n{\n    public partial class HotkeysPage\n    {\n        public HotkeysPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/ImageOverlaysPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.ImageOverlaysPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      Title=\"Image Overlays\">\n    <Grid>\n        <DockPanel DataContext=\"{Binding CustomImageOverlays, Source={StaticResource ServiceLocator}}\">\n            <Label DockPanel.Dock=\"Top\"\n                   Margin=\"5,3\"\n                   Content=\"Size of Preview considers Resize to be active\"\n                   Opacity=\"0.8\"/>\n\n            <DockPanel DockPanel.Dock=\"Top\">\n                <captura:ModernButton ToolTip=\"Add\"\n                                      Command=\"{Binding AddCommand}\"\n                                      IconData=\"{Binding Icons.Add, Source={StaticResource ServiceLocator}}\"/>\n\n                <Label Content=\"Add More\"/>\n            </DockPanel>\n\n            <ListView Margin=\"5\"\n                      ItemsSource=\"{Binding Collection}\"\n                      SelectedItem=\"{Binding SelectedItem, Mode=TwoWay}\">\n                <ListView.ItemTemplate>\n                    <DataTemplate>\n                        <TextBlock Text=\"Image\"/>\n                    </DataTemplate>\n                </ListView.ItemTemplate>\n            </ListView>\n\n            <GridSplitter Width=\"1\"/>\n\n            <DockPanel Margin=\"10\"\n                       VerticalAlignment=\"Top\"\n                       Visibility=\"{Binding SelectedItem, Converter={StaticResource NotNullConverter}}\">\n                <captura:ImageOverlaySettingsControl DockPanel.Dock=\"Bottom\"\n                                                     Margin=\"0,5\"\n                                                     DataContext=\"{Binding SelectedItem}\"/>\n\n                <DockPanel DockPanel.Dock=\"Top\">\n                    <captura:ModernButton ToolTip=\"Remove\"\n                                          Command=\"{Binding RemoveCommand}\"\n                                          CommandParameter=\"{Binding SelectedItem}\"\n                                          IconData=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"\n                                          DockPanel.Dock=\"Right\"/>\n\n                    <CheckBox IsChecked=\"{Binding SelectedItem.Display, Mode=TwoWay}\"\n                              Content=\"Display\"/>\n                </DockPanel>\n\n                <Label Content=\"Source\"\n                       ContentStringFormat=\"{}{0}: \"/>\n\n                <Button Content=\"...\"\n                        DockPanel.Dock=\"Right\"\n                        Command=\"{Binding ChangeCommand}\"\n                        CommandParameter=\"{Binding SelectedItem}\"/>\n\n                <TextBox Text=\"{Binding SelectedItem.Source, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"\n                         Margin=\"5,0\"/>\n            </DockPanel>\n        </DockPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/ImageOverlaysPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class ImageOverlaysPage\n    {\n        public ImageOverlaysPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/InterfacePage.xaml",
    "content": "﻿<Page x:Class=\"Captura.InterfacePage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n      xmlns:loc=\"clr-namespace:Captura.Loc;assembly=Captura.Loc\"\n      DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\"\n      Title=\"UI\">\n    <Grid>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition/>\n            <ColumnDefinition Width=\"Auto\"/>\n            <ColumnDefinition/>\n        </Grid.ColumnDefinitions>\n        <ScrollViewer>\n            <StackPanel Margin=\"5\">\n                <DockPanel Margin=\"5,5,0,5\">\n                    <Path Data=\"{Binding Icons.Translate, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <Label Content=\"{Binding Language, Source={StaticResource Loc}, Mode=OneWay}\"\n                           ContentStringFormat=\"{}{0}:\"\n                           Margin=\"5,0,10,0\"/>\n                    <ComboBox VerticalAlignment=\"Center\"\n                              DataContext=\"{x:Static loc:LanguageManager.Instance}\"\n                              ItemsSource=\"{Binding AvailableCultures}\"\n                              SelectedValue=\"{Binding CurrentCulture, Mode=TwoWay}\">\n                        <ComboBox.ItemTemplate>\n                            <DataTemplate>\n                                <TextBlock Text=\"{Binding Mode=OneWay, Converter={StaticResource LanguageConverter}}\"/>\n                            </DataTemplate>\n                        </ComboBox.ItemTemplate>\n                    </ComboBox>\n                </DockPanel>\n\n                <CheckBox Content=\"{Binding AlwaysOnTop, Source={StaticResource Loc}, Mode=OneWay}\"\n                          IsChecked=\"{Binding Settings.UI.MainWindowTopmost}\"\n                          Margin=\"0,2\"/>\n\n                <CheckBox IsChecked=\"{Binding Settings.UI.DarkTheme}\"\n                          Click=\"DarkThemeClick\"\n                          Content=\"{Binding DarkTheme, Source={StaticResource Loc}, Mode=OneWay}\"\n                          Margin=\"0,5\"/>\n\n                <Grid Margin=\"0,5\">\n                    <Grid.ColumnDefinitions>\n                        <ColumnDefinition Width=\"Auto\"/>\n                        <ColumnDefinition Width=\"*\"/>\n                    </Grid.ColumnDefinitions>\n\n                    <Label Content=\"{Binding AccentColor, Source={StaticResource Loc}, Mode=OneWay}\"\n                           ContentStringFormat=\"{}{0}: \"\n                           Margin=\"0,5,5,5\"/>\n                    <xctk:ColorPicker SelectedColor=\"{DynamicResource AccentColor}\"\n                                      SelectedColorChanged=\"SelectedAccentColorChanged\"\n                                      Margin=\"0,5\"\n                                      Grid.Column=\"1\"/>\n                </Grid>\n            </StackPanel>\n        </ScrollViewer>\n        <GridSplitter Grid.Column=\"1\"\n                      Width=\"1\"\n                      Margin=\"7,0\"/>\n        <DockPanel Grid.Column=\"2\">\n            <Label Margin=\"0,10\"\n                   Content=\"{Binding TrayIcon, Source={StaticResource Loc}, Mode=OneWay}\"\n                   FontWeight=\"Bold\"\n                   FontSize=\"15\"\n                   DockPanel.Dock=\"Top\"/>\n\n            <Frame Source=\"TrayIconPage.xaml\"/>\n        </DockPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/InterfacePage.xaml.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Media;\nusing Captura.ViewModels;\nusing FirstFloor.ModernUI.Presentation;\n\nnamespace Captura\n{\n    public partial class InterfacePage\n    {\n        void SelectedAccentColorChanged(object Sender, RoutedPropertyChangedEventArgs<Color?> E)\n        {\n            if (E.NewValue != null && DataContext is ViewModelBase vm)\n            {\n                AppearanceManager.Current.AccentColor = E.NewValue.Value;\n\n                vm.Settings.UI.AccentColor = E.NewValue.Value.ToString();\n            }\n        }\n\n        void DarkThemeClick(object Sender, RoutedEventArgs E)\n        {\n            if (DataContext is ViewModelBase vm)\n            {\n                AppearanceManager.Current.ThemeSource = vm.Settings.UI.DarkTheme\n                    ? AppearanceManager.DarkThemeSource\n                    : AppearanceManager.LightThemeSource;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/KeystrokesPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.KeystrokesPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\">\n    <Grid>\n        <ScrollViewer DataContext=\"{Binding AboutViewModel, Source={StaticResource ServiceLocator}}\">\n            <StackPanel Margin=\"5\"\n                        DataContext=\"{Binding Settings.Keystrokes}\">\n                <CheckBox Content=\"Display\"\n                          IsChecked=\"{Binding Display, Mode=TwoWay}\"\n                          Margin=\"0,5\"/>\n\n                <CheckBox Content=\"{Binding KeystrokesSeparateFile, Source={StaticResource Loc}, Mode=OneWay}\"\n                          IsChecked=\"{Binding SeparateTextFile, Mode=TwoWay}\"\n                          Margin=\"0,3\"\n                          IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"/>\n\n                <DockPanel Margin=\"0,3\">\n                    <Label Content=\"{Binding Keymap, Source={StaticResource Loc}, Mode=OneWay}\"\n                           ContentStringFormat=\"{}{0}: \"\n                           Margin=\"0,0,5,0\"/>\n\n                    <ComboBox DataContext=\"{Binding Keymap, Source={StaticResource ServiceLocator}}\"\n                              ItemsSource=\"{Binding AvailableKeymaps}\"\n                              SelectedValue=\"{Binding SelectedKeymap, Mode=TwoWay}\"\n                              DisplayMemberPath=\"Name\"/>\n                </DockPanel>\n\n                <captura:TextOverlaySettingsControl Visibility=\"{Binding SeparateTextFile, Converter={StaticResource NegatingConverter}}\"\n                                                    Margin=\"0,3\"/>\n\n                <Grid Margin=\"0,3\"\n                      Visibility=\"{Binding SeparateTextFile, Converter={StaticResource NegatingConverter}}\">\n                    <Grid.ColumnDefinitions>\n                        <ColumnDefinition Width=\"Auto\"/>\n                        <ColumnDefinition/>\n                    </Grid.ColumnDefinitions>\n                    <Grid.RowDefinitions>\n                        <RowDefinition/>\n                        <RowDefinition/>\n                        <RowDefinition/>\n                        <RowDefinition/>\n                    </Grid.RowDefinitions>\n\n                    <Label ContentStringFormat=\"{}{0}: \"\n                           Margin=\"0,5,5,5\">\n                        <TextBlock TextWrapping=\"Wrap\"\n                                   Text=\"{Binding MaxTextLength, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                    </Label>\n                    <xctk:IntegerUpDown Minimum=\"1\"\n                                        Value=\"{Binding MaxTextLength, Mode=TwoWay}\"\n                                        Grid.Column=\"1\"\n                                        Margin=\"0,5\"/>\n\n                    <Label Content=\"{Binding Timeout, Source={StaticResource Loc}, Mode=OneWay}\"\n                           ContentStringFormat=\"{}{0}: \"\n                           Margin=\"0,5,5,5\"\n                           Grid.Row=\"1\"/>\n                    <xctk:IntegerUpDown Value=\"{Binding Timeout, Mode=TwoWay}\"\n                                        Minimum=\"1\"\n                                        Grid.Row=\"1\"\n                                        Grid.Column=\"1\"\n                                        Margin=\"0,5\"/>\n\n                    <Label Content=\"{Binding KeystrokesHistoryCount, Source={StaticResource Loc}, Mode=OneWay}\"\n                           ContentStringFormat=\"{}{0}: \"\n                           Margin=\"0,5,5,5\"\n                           Grid.Row=\"2\"/>\n                    <xctk:IntegerUpDown Value=\"{Binding HistoryCount, Mode=TwoWay}\"\n                                        Grid.Row=\"2\"\n                                        Grid.Column=\"1\"\n                                        Minimum=\"1\"\n                                        Margin=\"0,5\"/>\n\n                    <Label Content=\"{Binding KeystrokesHistorySpacing, Source={StaticResource Loc}, Mode=OneWay}\"\n                           ContentStringFormat=\"{}{0}: \"\n                           Margin=\"0,5,5,5\"\n                           Grid.Row=\"3\"/>\n                    <xctk:IntegerUpDown Value=\"{Binding HistorySpacing, Mode=TwoWay}\"\n                                        Grid.Row=\"3\"\n                                        Grid.Column=\"1\"\n                                        Margin=\"0,5\"/>\n                </Grid>\n\n                <CheckBox Content=\"Show Repeat Counter\"\n                          IsChecked=\"{Binding ShowRepeatCounter, Mode=TwoWay}\"\n                          Margin=\"0,3\"\n                          Visibility=\"{Binding SeparateTextFile, Converter={StaticResource NegatingConverter}}\"/>\n            </StackPanel>\n        </ScrollViewer>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/KeystrokesPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class KeystrokesPage\n    {\n        public KeystrokesPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/LicensesPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.Views.LicensesPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      Title=\"Licenses\"\n      DataContext=\"{Binding LicensesViewModel, Source={StaticResource ServiceLocator}}\">\n    <DockPanel>\n        <ListView ItemsSource=\"{Binding Licenses}\"\n                  SelectedItem=\"{Binding SelectedLicense, Mode=TwoWay}\"\n                  Width=\"200\"\n                  Padding=\"5,0\"\n                  BorderThickness=\"0,0,0.6,0\">\n            <ListView.ItemTemplate>\n                <DataTemplate>\n                    <TextBlock Text=\"{Binding Name, Mode=OneWay}\"/>\n                </DataTemplate>\n            </ListView.ItemTemplate>\n        </ListView>\n\n        <Border DataContext=\"{Binding SelectedLicense}\">\n            <DockPanel>\n                <Label Margin=\"5\"\n                       DockPanel.Dock=\"Top\">\n                    <TextBlock Text=\"{Binding Name}\"\n                               Style=\"{StaticResource Heading1}\"/>\n                </Label>\n\n                <ScrollViewer>\n                    <Label Margin=\"5\"\n                           VerticalContentAlignment=\"Top\">\n                        <TextBlock Text=\"{Binding Content}\"\n                                   TextWrapping=\"Wrap\"/>\n                    </Label>\n                </ScrollViewer>\n            </DockPanel>\n        </Border>\n    </DockPanel>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/LicensesPage.xaml.cs",
    "content": "﻿namespace Captura.Views\n{\n    public partial class LicensesPage\n    {\n        public LicensesPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/MainPage.xaml",
    "content": "﻿<Page xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\"\n      x:Class=\"Captura.MainPage\">\n    <DockPanel>\n        <Frame Source=\"HomePage.xaml\"\n               Margin=\"5\"/>\n    </DockPanel>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/MainPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class MainPage\n    {\n    }\n}"
  },
  {
    "path": "src/Captura/Pages/MouseOverlayPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.MouseOverlayPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n      Title=\"Mouse Overlay\">\n    <Grid>\n        <ScrollViewer>\n            <StackPanel DataContext=\"{Binding AboutViewModel, Source={StaticResource ServiceLocator}}\">\n                <Label Content=\"{Binding MousePointer, Source={StaticResource Loc}, Mode=OneWay}\"\n                       FontWeight=\"DemiBold\"\n                       Margin=\"5,5,5,0\"/>\n\n                <StackPanel Margin=\"5\"\n                            DataContext=\"{Binding Settings.MousePointerOverlay}\">\n\n                    <CheckBox Content=\"Display\"\n                              IsChecked=\"{Binding Display, Mode=TwoWay}\"\n                              Margin=\"0,5\"/>\n\n                    <Grid>\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width=\"Auto\"/>\n                            <ColumnDefinition Width=\"*\"/>\n                        </Grid.ColumnDefinitions>\n                        <Grid.RowDefinitions>\n                            <RowDefinition/>\n                            <RowDefinition/>\n                        </Grid.RowDefinitions>\n\n                        <Label Content=\"{Binding Radius, Source={StaticResource Loc}, Mode=OneWay}\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"/>\n                        <xctk:IntegerUpDown Value=\"{Binding Radius, Mode=TwoWay}\"\n                                            Minimum=\"1\"\n                                            Margin=\"0,5\"\n                                            Grid.Column=\"1\"/>\n\n                        <Label Content=\"{Binding Color, Source={StaticResource Loc}, Mode=OneWay}\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"\n                               Grid.Row=\"1\"/>\n                        <xctk:ColorPicker SelectedColor=\"{Binding Color, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                                          Grid.Row=\"1\"\n                                          Grid.Column=\"1\"\n                                          Margin=\"0,5\"/>\n                    </Grid>\n\n                    <Grid>\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width=\"Auto\"/>\n                            <ColumnDefinition Width=\"Auto\"/>\n                            <ColumnDefinition Width=\"*\"/>\n                            <ColumnDefinition Width=\"*\"/>\n                        </Grid.ColumnDefinitions>\n\n                        <Path Data=\"{Binding Icons.Border, Source={StaticResource ServiceLocator}}\"\n                              Width=\"15\"\n                              Height=\"15\"\n                              Margin=\"0,0,10,0\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              VerticalAlignment=\"Center\"/>\n\n                        <Label Content=\"Border\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"\n                               Grid.Column=\"1\"/>\n\n                        <xctk:IntegerUpDown Value=\"{Binding BorderThickness, Mode=TwoWay}\"\n                                            Grid.Column=\"2\"\n                                            Margin=\"5\"/>\n\n                        <xctk:ColorPicker SelectedColor=\"{Binding BorderColor, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                                          Grid.Column=\"3\"\n                                          Margin=\"0,5\"/>\n                    </Grid>\n                </StackPanel>\n\n                <Label Content=\"{Binding MouseClicks, Source={StaticResource Loc}, Mode=OneWay}\"\n                       FontWeight=\"DemiBold\"\n                       Margin=\"5,10,5,0\"/>\n\n                <StackPanel Margin=\"5\"\n                            DataContext=\"{Binding Settings.Clicks}\">\n                    <CheckBox Content=\"Display Clicks\"\n                              IsChecked=\"{Binding Display, Mode=TwoWay}\"\n                              Margin=\"0,5\"/>\n\n                    <Grid>\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width=\"Auto\"/>\n                            <ColumnDefinition Width=\"*\"/>\n                        </Grid.ColumnDefinitions>\n                        <Grid.RowDefinitions>\n                            <RowDefinition/>\n                            <RowDefinition/>\n                            <RowDefinition/>\n                            <RowDefinition/>\n                        </Grid.RowDefinitions>\n\n                        <Label Content=\"{Binding Radius, Source={StaticResource Loc}, Mode=OneWay}\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"/>\n                        <xctk:IntegerUpDown Value=\"{Binding Radius, Mode=TwoWay}\"\n                                            Minimum=\"1\"\n                                            Margin=\"0,5\"\n                                            Grid.Column=\"1\"/>\n\n                        <Label Content=\"{Binding Color, Source={StaticResource Loc}, Mode=OneWay}\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"\n                               Grid.Row=\"1\"/>\n                        <xctk:ColorPicker SelectedColor=\"{Binding Color, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                                          Grid.Row=\"1\"\n                                          Grid.Column=\"1\"\n                                          Margin=\"0,5\"/>\n\n                        <Label Content=\"{Binding MouseRightClickColor, Source={StaticResource Loc}, Mode=OneWay}\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"\n                               Grid.Row=\"2\"/>\n                        <xctk:ColorPicker SelectedColor=\"{Binding RightClickColor, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                                          Grid.Row=\"2\"\n                                          Grid.Column=\"1\"\n                                          Margin=\"0,5\"/>\n\n                        <Label Content=\"{Binding MouseMiddleClickColor, Source={StaticResource Loc}, Mode=OneWay}\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"\n                               Grid.Row=\"3\"/>\n                        <xctk:ColorPicker SelectedColor=\"{Binding MiddleClickColor, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                                          Grid.Row=\"3\"\n                                          Grid.Column=\"1\"\n                                          Margin=\"0,5\"/>\n                    </Grid>\n\n                    <Grid>\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width=\"Auto\"/>\n                            <ColumnDefinition Width=\"Auto\"/>\n                            <ColumnDefinition Width=\"*\"/>\n                            <ColumnDefinition Width=\"*\"/>\n                        </Grid.ColumnDefinitions>\n\n                        <Path Data=\"{Binding Icons.Border, Source={StaticResource ServiceLocator}}\"\n                              Width=\"15\"\n                              Height=\"15\"\n                              Margin=\"0,0,10,0\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              VerticalAlignment=\"Center\"/>\n\n                        <Label Content=\"Border\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"\n                               Grid.Column=\"1\"/>\n\n                        <xctk:IntegerUpDown Value=\"{Binding BorderThickness, Mode=TwoWay}\"\n                                            Grid.Column=\"2\"\n                                            Margin=\"5\"/>\n\n                        <xctk:ColorPicker SelectedColor=\"{Binding BorderColor, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                                          Grid.Column=\"3\"\n                                          Margin=\"0,5\"/>\n                    </Grid>\n                </StackPanel>\n\n                <Label Content=\"Mouse Scroll\"\n                       FontWeight=\"DemiBold\"\n                       Margin=\"5,10,5,0\"/>\n                <Label Content=\"Horizontal scrolls aren't displayed correctly\"\n                       FontWeight=\"Light\"\n                       FontSize=\"9\"\n                       Margin=\"5,0\"/>\n\n                <StackPanel Margin=\"5\"\n                            DataContext=\"{Binding Settings.Clicks}\"\n                            IsEnabled=\"{Binding Display}\">\n                    <CheckBox Content=\"Display Scroll\"\n                              IsChecked=\"{Binding DisplayScroll, Mode=TwoWay}\"\n                              Margin=\"0,5\"/>\n\n                    <Grid>\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width=\"Auto\"/>\n                            <ColumnDefinition Width=\"*\"/>\n                        </Grid.ColumnDefinitions>\n                        <Grid.RowDefinitions>\n                            <RowDefinition/>\n                            <RowDefinition/>\n                        </Grid.RowDefinitions>\n\n                        <Label Content=\"Circle Color\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"/>\n                        <xctk:ColorPicker SelectedColor=\"{Binding ScrollCircleColor, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                                          Grid.Row=\"0\"\n                                          Grid.Column=\"1\"\n                                          Margin=\"0,5\"/>\n\n                        <Label Content=\"Arrow Color\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"0,5,5,5\"\n                               Grid.Row=\"1\"\n                               Grid.Column=\"0\"/>\n                        <xctk:ColorPicker SelectedColor=\"{Binding ScrollArrowColor, Converter={StaticResource WpfColorConverter}, Mode=TwoWay}\"\n                                          Grid.Row=\"1\"\n                                          Grid.Column=\"1\"\n                                          Margin=\"0,5\"/>\n                    </Grid>\n                </StackPanel>\n            </StackPanel>\n        </ScrollViewer>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/MouseOverlayPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class MouseOverlayPage\n    {\n        public MouseOverlayPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/OverlayPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.OverlayPage\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:local=\"clr-namespace:Captura\"\n        xmlns:mui=\"http://firstfloorsoftware.com/ModernUI\"\n        mc:Ignorable=\"d\"\n        Title=\"{Binding Overlays, Source={StaticResource Loc}, Mode=OneWay}\"\n        SizeChanged=\"OverlayWindow_OnSizeChanged\">\n    <Grid Background=\"{DynamicResource WindowBackground}\">\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition Width=\"280\" MinWidth=\"280\"/>\n            <ColumnDefinition Width=\"Auto\"/>\n            <ColumnDefinition/>\n        </Grid.ColumnDefinitions>\n        \n        <TabControl Background=\"Transparent\"\n                    BorderThickness=\"0\">\n            <TabControl.ContentTemplate>\n                <DataTemplate>\n                    <mui:TransitioningContentControl Content=\"{Binding}\"/>\n                </DataTemplate>\n            </TabControl.ContentTemplate>\n            <TabItem Header=\"{Binding Keystrokes, Source={StaticResource Loc}, Mode=OneWay}\">\n                <Frame Source=\"../Pages/KeystrokesPage.xaml\"/>\n            </TabItem>\n            <TabItem Header=\"Mouse\">\n                <Frame Source=\"../Pages/MouseOverlayPage.xaml\"/>\n            </TabItem>\n            <TabItem Header=\"Elapsed\"\n                     DataContext=\"{Binding AboutViewModel, Source={StaticResource ServiceLocator}}\">\n                <StackPanel DataContext=\"{Binding Settings.Elapsed}\">\n                    <CheckBox Content=\"Display\"\n                              IsChecked=\"{Binding Display, Mode=TwoWay}\"\n                              Margin=\"0,5\"/>\n                    <local:TextOverlaySettingsControl Margin=\"5\"\n                                                      DockPanel.Dock=\"Bottom\"/>\n                </StackPanel>\n            </TabItem>\n            <TabItem Header=\"Censor\">\n                <Frame Source=\"../Pages/CensorOverlaysPage.xaml\"/>\n            </TabItem>\n            <TabItem Header=\"Text\">\n                <Frame Source=\"../Pages/TextOverlaysPage.xaml\"/>\n            </TabItem>\n            <TabItem Header=\"Images\">\n                <Frame Source=\"../Pages/ImageOverlaysPage.xaml\"/>\n            </TabItem>\n        </TabControl>\n\n        <GridSplitter Width=\"3\"\n                      Grid.Column=\"1\"\n                      Opacity=\"0.3\"\n                      Background=\"{StaticResource ItemText}\"/>\n        \n        <DockPanel Grid.Column=\"2\">\n            <Label DockPanel.Dock=\"Top\"\n                   Content=\"{Binding Preview, Source={StaticResource Loc}}\"\n                   Padding=\"5\"/>\n\n            <Grid Background=\"Transparent\"\n                  VerticalAlignment=\"Center\"\n                  HorizontalAlignment=\"Center\"\n                  MouseDown=\"UIElement_OnMouseDown\"\n                  MouseUp=\"UIElement_OnMouseUp\"\n                  MouseMove=\"UIElement_OnMouseMove\"\n                  MouseLeave=\"UIElement_OnMouseLeave\">\n                <Image Name=\"Img\"\n                       Stretch=\"Uniform\"\n                       SizeChanged=\"OverlayWindow_OnSizeChanged\"/>\n                \n                <Grid>\n                    <Grid.LayoutTransform>\n                        <ScaleTransform x:Name=\"Scale\"/>\n                    </Grid.LayoutTransform>\n\n                    <Grid Name=\"Grid\"/>\n                    \n                    <Ellipse Name=\"MousePointer\"\n                             Visibility=\"Collapsed\"\n                             HorizontalAlignment=\"Left\"\n                             VerticalAlignment=\"Top\"/>\n\n                    <Ellipse Name=\"MouseClick\"\n                             Opacity=\"0\"\n                             HorizontalAlignment=\"Left\"\n                             VerticalAlignment=\"Top\"/>\n                </Grid>\n            </Grid>\n        </DockPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/OverlayPage.xaml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Collections.Specialized;\nusing System.Linq;\nusing System.Reactive.Linq;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Documents;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Animation;\nusing Captura.MouseKeyHook;\nusing Captura.Video;\nusing Captura.ViewModels;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\nusing Color = System.Windows.Media.Color;\nusing Point = System.Windows.Point;\n\nnamespace Captura\n{\n    public partial class OverlayPage\n    {\n        OverlayPage()\n        {\n            InitializeComponent();\n\n            Loaded += OnLoaded;\n\n            Unloaded += (S, E) => Grid.Children.Clear();\n        }\n\n        static readonly Lazy<OverlayPage> LazyInstance = new Lazy<OverlayPage>(() => new OverlayPage());\n\n        public static OverlayPage Instance => LazyInstance.Value;\n\n        void AddToGrid(LayerFrame Frame, bool CanResize)\n        {\n            Grid.Children.Add(Frame);\n\n            Panel.SetZIndex(Frame, 0);\n\n            var layer = AdornerLayer.GetAdornerLayer(Frame);\n            var adorner = new OverlayPositionAdorner(Frame, CanResize);\n            layer.Add(adorner);\n\n            adorner.PositionUpdated += Frame.RaisePositionChanged;\n        }\n\n        LayerFrame Generate(PositionedOverlaySettings Settings, string Text, Color BackgroundColor)\n        {\n            var control = new LayerFrame\n            {\n                Border =\n                {\n                    Background = new SolidColorBrush(BackgroundColor)\n                },\n                HorizontalAlignment = HorizontalAlignment.Left,\n                VerticalAlignment = VerticalAlignment.Top,\n                Label =\n                {\n                    Content = Text,\n                    Foreground = new SolidColorBrush(Colors.White)\n                }\n            };\n\n            var vm = new PositionOverlayReactor(Settings);\n\n            control.BindOne(HorizontalAlignmentProperty, vm.HAlignment);\n            control.BindOne(VerticalAlignmentProperty, vm.VAlignment);\n            control.BindOne(MarginProperty, vm.Margin);\n\n            control.PositionUpdated += Rect =>\n            {\n                Settings.X = (int)Rect.X;\n                Settings.Y = (int)Rect.Y;\n            };\n\n            return control;\n        }\n\n        LayerFrame Image(ImageOverlaySettings Settings, string Text)\n        {\n            var control = Generate(Settings, Text, Colors.Brown);\n\n            var vm = new ImageOverlayReactor(Settings);\n\n            control.Bind(WidthProperty, vm.Width);\n            control.Bind(HeightProperty, vm.Height);\n\n            control.BindOne(OpacityProperty, vm.Opacity);\n\n            return control;\n        }\n\n        LayerFrame Text(TextOverlaySettings Settings, string Text)\n        {\n            var control = Generate(Settings, Text, Settings.BackgroundColor.ToWpfColor());\n\n            var vm = new TextOverlayReactor(Settings);\n\n            control.Label.BindOne(FontFamilyProperty, vm.FontFamily);\n            control.Label.BindOne(FontSizeProperty, vm.FontSize);\n\n            // Border.PaddingProperty is different from PaddingProperty\n            control.Border.BindOne(Border.PaddingProperty, vm.Padding);\n\n            control.Label.BindOne(ForegroundProperty, vm.Foreground);\n            control.Border.BindOne(BackgroundProperty, vm.Background);\n\n            control.Border.BindOne(Border.BorderThicknessProperty, vm.BorderThickness);\n            control.Border.BindOne(Border.BorderBrushProperty, vm.BorderBrush);\n            control.Border.BindOne(Border.CornerRadiusProperty, vm.CornerRadius);\n\n            return control;\n        }\n\n        LayerFrame Censor(CensorOverlaySettings Settings)\n        {\n            var control = Generate(Settings, \"Censored\", Colors.Black);\n\n            var vm = new CensorOverlayReactor(Settings);\n\n            control.Bind(WidthProperty, vm.Width);\n            control.Bind(HeightProperty, vm.Height);\n\n            control.BindOne(VisibilityProperty, vm.Visible);\n\n            return control;\n        }\n\n        LayerFrame Keystrokes(KeystrokesSettings Settings)\n        {\n            var control = Text(Settings, \"Keystrokes\");\n\n            var visibilityProp = Settings\n                .ObserveProperty(M => M.SeparateTextFile)\n                .Select(M => M ? Visibility.Collapsed : Visibility.Visible)\n                .ToReadOnlyReactivePropertySlim();\n\n            control.BindOne(VisibilityProperty, visibilityProp);\n\n            return control;\n        }\n\n        readonly List<LayerFrame> _textOverlays = new List<LayerFrame>();\n        readonly List<LayerFrame> _imageOverlays = new List<LayerFrame>();\n        readonly List<LayerFrame> _censorOverlays = new List<LayerFrame>();\n\n        void UpdateOverlays<TSettings>(IEnumerable<TSettings> Settings,\n            List<LayerFrame> LayerFrames,\n            Func<TSettings, LayerFrame> LayerFrameGenerator,\n            bool CanResize,\n            int ZIndex)\n        {\n            foreach (var layerFrame in LayerFrames)\n            {\n                Grid.Children.Remove(layerFrame);\n            }\n\n            LayerFrames.Clear();\n\n            LayerFrames.AddRange(Settings.Select(LayerFrameGenerator));\n\n            foreach (var layerFrame in LayerFrames)\n            {\n                AddToGrid(layerFrame, CanResize);\n\n                Panel.SetZIndex(layerFrame, ZIndex);\n            }\n        }\n\n        void UpdateCensorOverlays(IEnumerable<CensorOverlaySettings> Settings)\n        {\n            UpdateOverlays(Settings, _censorOverlays, Censor, true, -1);\n        }\n\n        void UpdateTextOverlays(IEnumerable<CustomOverlaySettings> Settings)\n        {\n            UpdateOverlays(Settings, _textOverlays, Setting =>\n            {\n                var control = Text(Setting, Setting.Text);\n\n                var visibilityProp = Setting\n                    .ObserveProperty(M => M.Display)\n                    .Select(M => M ? Visibility.Visible : Visibility.Collapsed)\n                    .ToReadOnlyReactivePropertySlim();\n\n                control.BindOne(VisibilityProperty, visibilityProp);\n\n                var textProp = Setting\n                    .ObserveProperty(M => M.Text)\n                    .ToReadOnlyReactivePropertySlim();\n\n                control.Label.BindOne(ContentProperty, textProp);\n\n                return control;\n            }, false, 1);\n        }\n\n        void UpdateImageOverlays(IEnumerable<CustomImageOverlaySettings> Settings)\n        {\n            UpdateOverlays(Settings, _imageOverlays, Setting =>\n            {\n                var control = Image(Setting, Setting.Source);\n\n                var img = new Image\n                {\n                    Stretch = Stretch.Fill\n                };\n\n                control.Label.Content = img;\n\n                var visibilityProp = Setting\n                    .ObserveProperty(M => M.Display)\n                    .Select(M => M ? Visibility.Visible : Visibility.Collapsed)\n                    .ToReadOnlyReactivePropertySlim();\n\n                control.BindOne(VisibilityProperty, visibilityProp);\n\n                var srcProp = Setting\n                    .ObserveProperty(M => M.Source)\n                    .ToReadOnlyReactivePropertySlim();\n\n                img.BindOne(System.Windows.Controls.Image.SourceProperty, srcProp);\n\n                return control;\n            }, true, 2);\n        }\n\n        async void OnLoaded(object Sender, RoutedEventArgs RoutedEventArgs)\n        {\n            await UpdateBackground();\n\n            PlaceOverlays();\n\n            UpdateScale();\n        }\n\n        async Task UpdateBackground()\n        {\n            Img.Source = await WpfExtensions.GetBackground();\n        }\n\n        void UpdateScale()\n        {\n            if (Img.Source == null)\n                return;\n\n            var scaleX = Img.ActualWidth / Img.Source.Width;\n            var scaleY = Img.ActualHeight / Img.Source.Height;\n\n            Scale.ScaleX = scaleX / Dpi.X;\n            Scale.ScaleY = scaleY / Dpi.Y;\n        }\n\n        void PlaceOverlays()\n        {\n            var settings = ServiceProvider.Get<Settings>();\n\n            var censorOverlayVm = ServiceProvider.Get<CensorOverlaysViewModel>();\n\n            UpdateCensorOverlays(censorOverlayVm.Collection);\n            (censorOverlayVm.Collection as INotifyCollectionChanged).CollectionChanged += (S, E) => UpdateCensorOverlays(censorOverlayVm.Collection);\n\n            PrepareMousePointer(settings.MousePointerOverlay);\n            PrepareMouseClick(settings.Clicks);\n\n            var keystrokes = Keystrokes(settings.Keystrokes);\n            AddToGrid(keystrokes, false);\n\n            var elapsed = Text(settings.Elapsed, \"00:00:00\");\n            AddToGrid(elapsed, false);\n\n            var textOverlayVm = ServiceProvider.Get<CustomOverlaysViewModel>();\n\n            UpdateTextOverlays(textOverlayVm.Collection);\n            (textOverlayVm.Collection as INotifyCollectionChanged).CollectionChanged += (S, E) => UpdateTextOverlays(textOverlayVm.Collection);\n\n            var imgOverlayVm = ServiceProvider.Get<CustomImageOverlaysViewModel>();\n\n            UpdateImageOverlays(imgOverlayVm.Collection);\n            (imgOverlayVm.Collection as INotifyCollectionChanged).CollectionChanged += (S, E) => UpdateImageOverlays(imgOverlayVm.Collection);\n        }\n\n        void PrepareMouseClick(MouseClickSettings Settings)\n        {\n            void Update()\n            {\n                var d = (Settings.Radius + Settings.BorderThickness) * 2;\n\n                MouseClick.Width = MouseClick.Height = d;\n                MouseClick.StrokeThickness = Settings.BorderThickness;\n                MouseClick.Stroke = new SolidColorBrush(Settings.BorderColor.ToWpfColor());\n            }\n\n            Update();\n            \n            Settings.PropertyChanged += (S, E) => Dispatcher.Invoke(Update);\n        }\n\n        void PrepareMousePointer(MouseOverlaySettings Settings)\n        {\n            void Update()\n            {\n                var d = (Settings.Radius + Settings.BorderThickness) * 2;\n\n                MousePointer.Width = MousePointer.Height = d;\n                MousePointer.StrokeThickness = Settings.BorderThickness;\n                MousePointer.Stroke = new SolidColorBrush(Settings.BorderColor.ToWpfColor());\n                MousePointer.Fill = new SolidColorBrush(Settings.Color.ToWpfColor());\n            }\n\n            Update();\n\n            Settings.PropertyChanged += (S, E) => Dispatcher.Invoke(Update);\n        }\n\n        void OverlayWindow_OnSizeChanged(object Sender, SizeChangedEventArgs E)\n        {\n            UpdateScale();\n        }\n\n        static Color GetClickColor(MouseButton Button)\n        {\n            var settings = ServiceProvider.Get<Settings>();\n\n            switch (Button)\n            {\n                case MouseButton.Middle:\n                    return settings.Clicks.MiddleClickColor.ToWpfColor();\n\n                case MouseButton.Right:\n                    return settings.Clicks.RightClickColor.ToWpfColor();\n                    \n                default:\n                    return settings.Clicks.Color.ToWpfColor();\n            }\n        }\n\n        bool _dragging;\n\n        void UpdateMouseClickPosition(Point Position)\n        {\n            MouseClick.Margin = new Thickness(Position.X - MouseClick.ActualWidth / 2, Position.Y - MouseClick.ActualHeight / 2, 0, 0);\n        }\n\n        void UIElement_OnMouseDown(object Sender, MouseButtonEventArgs E)\n        {\n            _dragging = true;\n\n            UpdateMouseClickPosition(E.GetPosition(Grid));\n\n            MouseClick.Fill = new SolidColorBrush(GetClickColor(E.ChangedButton));\n\n            MouseClick.BeginAnimation(OpacityProperty, new DoubleAnimation(1, new Duration(TimeSpan.FromMilliseconds(200))));\n        }\n\n        void MouseClickEnd()\n        {\n            MouseClick.BeginAnimation(OpacityProperty, new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(300))));\n\n            _dragging = false;\n        }\n\n        void UIElement_OnMouseUp(object Sender, MouseButtonEventArgs E)\n        {\n            MouseClickEnd();\n        }\n\n        bool IsOutsideGrid(Point Point)\n        {\n            return Point.X <= 0 || Point.Y <= 0\n                   || Point.X + MouseClick.ActualWidth / 2 >= Grid.ActualWidth\n                   || Point.Y + MouseClick.ActualHeight / 2 >= Grid.ActualHeight;\n        }\n\n        void UIElement_OnMouseMove(object Sender, MouseEventArgs E)\n        {\n            if (ServiceProvider.Get<Settings>().MousePointerOverlay.Display)\n                MousePointer.Visibility = Visibility.Visible;\n\n            var position = E.GetPosition(Grid);\n\n            if (IsOutsideGrid(position))\n            {\n                MousePointer.Visibility = Visibility.Collapsed;\n\n                return;\n            }\n\n            if (_dragging)\n            {\n                UpdateMouseClickPosition(position);\n            }\n\n            position.X -= MouseClick.ActualWidth / 2;\n            position.Y -= MouseClick.ActualHeight / 2;\n\n            MousePointer.Margin = new Thickness(position.X, position.Y, 0, 0);\n        }\n\n        void UIElement_OnMouseLeave(object Sender, MouseEventArgs E)\n        {\n            MouseClickEnd();\n\n            MousePointer.Visibility = Visibility.Collapsed;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/ProxyPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.Views.ProxyPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      DataContext=\"{Binding ProxySettingsViewModel, Source={StaticResource ServiceLocator}}\"\n      Title=\"{Binding Proxy, Source={StaticResource Loc}, Mode=OneWay}\">\n    <Grid Margin=\"5,0\">\n        <StackPanel>\n            <ListView ItemsSource=\"{Binding ProxyTypes}\"\n                      SelectedValue=\"{Binding ProxySettings.Type}\"\n                      Margin=\"0,0,0,10\"\n                      SelectionMode=\"Single\"\n                      BorderThickness=\"0.4\"\n                      HorizontalContentAlignment=\"Center\">\n                <ListView.ItemsPanel>\n                    <ItemsPanelTemplate>\n                        <UniformGrid Rows=\"1\"/>\n                    </ItemsPanelTemplate>\n                </ListView.ItemsPanel>\n                <ListView.ItemTemplate>\n                    <DataTemplate>\n                        <Grid Background=\"#01000000\">\n                            <TextBlock Text=\"{Binding}\"\n                                       HorizontalAlignment=\"Center\"/>\n                        </Grid>\n                    </DataTemplate>\n                </ListView.ItemTemplate>\n            </ListView>\n            \n            <Grid Visibility=\"{Binding CanHost.Value, Converter={StaticResource BoolToVisibilityConverter}}\">\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"*\"/>\n                </Grid.ColumnDefinitions>\n                <Grid.RowDefinitions>\n                    <RowDefinition/>\n                    <RowDefinition/>\n                </Grid.RowDefinitions>\n\n                <Label Content=\"{Binding Host, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Margin=\"0,5,5,5\"/>\n\n                <TextBox Text=\"{Binding ProxySettings.Host}\"\n                         Grid.Column=\"1\"\n                         Margin=\"0,5\"/>\n\n                <Label Content=\"{Binding Port, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Grid.Row=\"1\"\n                       Margin=\"0,5,5,5\"/>\n\n                <xctk:IntegerUpDown Value=\"{Binding ProxySettings.Port}\"\n                                    Grid.Row=\"1\"\n                                    Grid.Column=\"1\"\n                                    Margin=\"0,5\"/>\n            </Grid>\n\n            <CheckBox IsChecked=\"{Binding ProxySettings.Authenticate}\"\n                      Visibility=\"{Binding CanAuth.Value, Converter={StaticResource BoolToVisibilityConverter}}\"\n                      Margin=\"0,10,0,5\">\n                <TextBlock TextWrapping=\"Wrap\"\n                           Text=\"{Binding UseProxyAuth, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </CheckBox>\n\n            <Grid Visibility=\"{Binding CanAuthCred.Value, Converter={StaticResource BoolToVisibilityConverter}}\">\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition/>\n                </Grid.ColumnDefinitions>\n                <Grid.RowDefinitions>\n                    <RowDefinition/>\n                    <RowDefinition/>\n                </Grid.RowDefinitions>\n\n                <Label Content=\"{Binding UserName, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Margin=\"0,5,5,5\"/>\n\n                <TextBox Text=\"{Binding ProxySettings.UserName}\"\n                         Grid.Column=\"1\"\n                         Margin=\"0,5\"/>\n\n                <Label Content=\"{Binding Password, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Margin=\"0,5,5,5\"\n                       Grid.Row=\"1\"/>\n\n                <captura:ModernPasswordBox Password=\"{Binding ProxySettings.Password, Mode=TwoWay}\"\n                                           Grid.Row=\"1\"\n                                           Grid.Column=\"1\"\n                                           Margin=\"0,5\"/>\n            </Grid>\n        </StackPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/ProxyPage.xaml.cs",
    "content": "﻿namespace Captura.Views\n{\n    public partial class ProxyPage\n    {\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/RecentPage.xaml",
    "content": "<Page x:Class=\"Captura.Views.RecentPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:local=\"clr-namespace:Captura\"\n      DataContext=\"{Binding RecentViewModel, Source={StaticResource ServiceLocator}}\"\n      Title=\"{Binding Recent, Source={StaticResource Loc}, Mode=OneWay}\">\n    <Grid>\n        <DockPanel Margin=\"5,0,0,0\">\n            <DockPanel DockPanel.Dock=\"Top\"\n                       Margin=\"0,0,0,10\">\n                <Button Content=\"{Binding Clear, Source={StaticResource Loc}, Mode=OneWay}\"\n                        ToolTip=\"{Binding ClearRecentList, Source={StaticResource Loc}, Mode=OneWay}\"\n                        DockPanel.Dock=\"Right\"\n                        Command=\"{Binding ClearCommand}\"/>\n            </DockPanel>\n\n            <ItemsControl Margin=\"0,0,0,10\"\n                          ItemsSource=\"{Binding Items}\"\n                          Style=\"{StaticResource VirtualizingItemsControl}\">\n                <ItemsControl.ItemTemplate>\n                    <DataTemplate>\n                        <local:RecentItem/>\n                    </DataTemplate>\n                </ItemsControl.ItemTemplate>\n            </ItemsControl>\n        </DockPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/RecentPage.xaml.cs",
    "content": "﻿namespace Captura.Views\n{\n    public partial class RecentPage\n    {\n    }\n}"
  },
  {
    "path": "src/Captura/Pages/ScreenShotsPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.ScreenShotsPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      Title=\"{Binding ScreenShot, Source={StaticResource Loc}, Mode=OneWay}\">\n    <Grid DataContext=\"{Binding ScreenShotViewModel, Source={StaticResource ServiceLocator}}\">\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition/>\n            <ColumnDefinition Width=\"Auto\"/>\n            <ColumnDefinition/>\n        </Grid.ColumnDefinitions>\n        <StackPanel Margin=\"5,0,0,0\">\n            <CheckBox IsChecked=\"{Binding Settings.UI.HideOnFullScreenShot}\"\n                      Margin=\"0,5\">\n                <TextBlock TextWrapping=\"Wrap\"\n                           Text=\"{Binding HideOnFullScreenShot, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </CheckBox>\n\n            <CheckBox IsChecked=\"{Binding Settings.ScreenShots.WindowShotTransparent}\"\n                      Margin=\"0,5\">\n                <TextBlock TextWrapping=\"Wrap\"\n                           Text=\"{Binding WindowScreenShotTransparency, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </CheckBox>\n\n            <DockPanel Margin=\"0,5\">\n                <Label Content=\"{Binding ImgFormat, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Margin=\"0,0,5,0\"/>\n\n                <ComboBox VerticalAlignment=\"Center\"\n                          ItemsSource=\"{Binding ScreenShotImageFormats}\"\n                          SelectedItem=\"{Binding Settings.ScreenShots.ImageFormat, Mode=TwoWay}\"/>\n            </DockPanel>\n\n            <DockPanel Margin=\"0,5\">\n                <Label Content=\"External Editor\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Margin=\"0,0,5,0\"/>\n\n                <TextBox Text=\"{Binding Settings.ScreenShots.ExternalEditor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"\n                         Margin=\"5\"/>\n            </DockPanel>\n        </StackPanel>\n        <GridSplitter Grid.Column=\"1\"\n                      Width=\"1\"\n                      Margin=\"7,0\"/>\n        <StackPanel Grid.Column=\"2\">\n            <StackPanel.Resources>\n                <Style TargetType=\"Path\" BasedOn=\"{StaticResource {x:Type Path}}\">\n                    <Setter Property=\"LayoutTransform\">\n                        <Setter.Value>\n                            <ScaleTransform ScaleX=\"0.6\" ScaleY=\"0.6\"/>\n                        </Setter.Value>\n                    </Setter>\n                    <Setter Property=\"Margin\" Value=\"0,0,5,0\"/>\n                    <Setter Property=\"VerticalAlignment\" Value=\"Center\"/>\n                </Style>\n                <Style TargetType=\"CheckBox\" BasedOn=\"{StaticResource {x:Type CheckBox}}\">\n                    <Setter Property=\"Margin\" Value=\"0,4\"/>\n                </Style>\n            </StackPanel.Resources>\n            \n            <Label Content=\"Outputs\"\n                   FontWeight=\"Bold\"\n                   Margin=\"0,0,0,10\"/>\n\n            <CheckBox IsChecked=\"{Binding DiskWriter.Active}\"\n                      IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n                <StackPanel Orientation=\"Horizontal\">\n                    <Path Data=\"{Binding Icons.NewFile, Source={StaticResource ServiceLocator}}\"/>\n                    <TextBlock Text=\"{Binding Disk, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                </StackPanel>\n            </CheckBox>\n\n            <CheckBox IsChecked=\"{Binding ClipboardWriter.Active}\"\n                      IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n                <StackPanel Orientation=\"Horizontal\">\n                    <Path Data=\"{Binding Icons.Clipboard, Source={StaticResource ServiceLocator}}\"/>\n                    <TextBlock Text=\"{Binding Clipboard, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                </StackPanel>\n            </CheckBox>\n\n            <CheckBox IsChecked=\"{Binding ImgurWriter.Active}\"\n                      IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n                <StackPanel Orientation=\"Horizontal\">\n                    <Path Data=\"{Binding Icons.Web, Source={StaticResource ServiceLocator}}\"/>\n                    <TextBlock Text=\"Imgur\"/>\n                </StackPanel>\n            </CheckBox>\n\n            <CheckBox IsChecked=\"{Binding EditorWriter.Active, Source={StaticResource ServiceLocator}}\"\n                      IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n                <StackPanel Orientation=\"Horizontal\">\n                    <Path Data=\"{Binding Icons.Pencil, Source={StaticResource ServiceLocator}}\"/>\n                    <TextBlock Text=\"{Binding ImageEditor, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                </StackPanel>\n            </CheckBox>\n        </StackPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/ScreenShotsPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class ScreenShotsPage\n    {\n        public ScreenShotsPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/SettingsPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.SettingsPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      Title=\"{Binding Configure, Source={StaticResource Loc}, Mode=OneWay}\">\n    <DockPanel>\n        <ScrollViewer>\n            <WrapPanel VerticalAlignment=\"Center\"\n                       HorizontalAlignment=\"Center\"\n                       MaxWidth=\"800\">\n                <WrapPanel.Resources>\n                    <Style TargetType=\"captura:ModernButton\" BasedOn=\"{StaticResource IconButton}\">\n                        <Setter Property=\"Command\" Value=\"GoToPage\"/>\n                    </Style>\n                </WrapPanel.Resources>\n\n                <captura:ModernButton Content=\"{Binding Video, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.Video, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/VideoPage.xaml\"/>\n\n                <captura:ModernButton Content=\"{Binding WebCam, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.Webcam, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"{Binding WebcamPage, Source={StaticResource ServiceLocator}}\"/>\n\n                <captura:ModernButton Content=\"{Binding Audio, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.Speaker, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/AudioPage.xaml\"/>\n\n                <captura:ModernButton Content=\"{Binding ScreenShot, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.Region, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/ScreenShotsPage.xaml\"/>\n\n                <captura:ModernButton Content=\"{Binding Recent, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.History, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/RecentPage.xaml\"/>\n\n                <captura:ModernButton Content=\"UI\"\n                                      IconData=\"{Binding Icons.Window, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/InterfacePage.xaml\"/>\n\n                <captura:ModernButton Content=\"FFmpeg\"\n                                      IconData=\"{Binding Icons.VideoFile, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/FFmpegPage.xaml\"/>\n\n                <captura:ModernButton Content=\"{Binding Hotkeys, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.Keyboard, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/HotkeysPage.xaml\"/>\n\n                <captura:ModernButton Content=\"{Binding Proxy, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.Web, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/ProxyPage.xaml\"/>\n\n                <captura:ModernButton Content=\"{Binding FileNaming, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.NewFile, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/FileNameFormatPage.xaml\"/>\n\n                <captura:ModernButton Content=\"{Binding Overlays, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.Arrow, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"{x:Static captura:OverlayPage.Instance}\"/>\n\n                <captura:ModernButton Content=\"{Binding About, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      IconData=\"{Binding Icons.Help, Source={StaticResource ServiceLocator}}\"\n                                      CommandParameter=\"/Pages/AboutPage.xaml\"/>\n            </WrapPanel>\n        </ScrollViewer>\n    </DockPanel>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/SettingsPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class SettingsPage\n    {\n        public SettingsPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/SoundsPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.SoundsPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n      DataContext=\"{Binding SoundsViewModel, Source={StaticResource ServiceLocator}}\"\n      Title=\"{Binding Sounds, Source={StaticResource Loc}, Mode=OneWay}\">\n    <Grid Margin=\"5,10\">\n        <ItemsControl Grid.IsSharedSizeScope=\"True\"\n                      ItemsSource=\"{Binding Items}\">\n            <ItemsControl.ItemTemplate>\n                <DataTemplate>\n                    <Grid>\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width=\"Auto\" SharedSizeGroup=\"Label\"/>\n                            <ColumnDefinition/>\n                            <ColumnDefinition Width=\"Auto\" SharedSizeGroup=\"Reset\"/>\n                            <ColumnDefinition Width=\"Auto\" SharedSizeGroup=\"Browse\"/>\n                        </Grid.ColumnDefinitions>\n\n                        <Label Content=\"{Binding SoundKind}\"\n                               ContentStringFormat=\"{}{0}: \"\n                               Margin=\"5\"/>\n\n                        <Border ToolTip=\"{Binding FileName}\"\n                                MouseUp=\"SetFile\"\n                                Cursor=\"Hand\"\n                                Grid.Column=\"1\"\n                                Margin=\"0,5\">\n                            <xctk:WatermarkTextBox IsReadOnly=\"True\"\n                                                   IsEnabled=\"False\"\n                                                   Text=\"{Binding FileName}\"\n                                                   Watermark=\"No Sound\"/>\n                        </Border>\n\n                        <Button Grid.Column=\"2\"\n                                Margin=\"5\"\n                                ToolTip=\"{Binding Reset, Source={StaticResource Loc}, Mode=OneWay}\"\n                                Command=\"{Binding ResetCommand}\"\n                                IsEnabled=\"{Binding FileName, Converter={StaticResource NotNullConverter}}\"\n                                VerticalContentAlignment=\"Center\">\n                            <Path Stretch=\"UniformToFill\"\n                                  Height=\"10\"\n                                  Width=\"9\"\n                                  Data=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"/>\n                        </Button>\n\n                        <Button Grid.Column=\"3\"\n                                Margin=\"0,5,5,5\"\n                                Command=\"{Binding SetCommand}\">\n                            <Path Stretch=\"UniformToFill\"\n                                  Height=\"4\"\n                                  Width=\"16\"\n                                  Data=\"{Binding Icons.More, Source={StaticResource ServiceLocator}}\"/>\n                        </Button>\n                    </Grid>\n                </DataTemplate>\n            </ItemsControl.ItemTemplate>\n        </ItemsControl>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/SoundsPage.xaml.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Input;\nusing Captura.ViewModels;\n\nnamespace Captura\n{\n    public partial class SoundsPage\n    {\n        public SoundsPage()\n        {\n            InitializeComponent();\n        }\n\n        void SetFile(object Sender, MouseButtonEventArgs E)\n        {\n            if (Sender is FrameworkElement element && element.DataContext is SoundsViewModelItem vm)\n            {\n                vm.SetCommand.ExecuteIfCan();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/TextOverlaysPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.TextOverlaysPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:captura=\"clr-namespace:Captura\">\n    <Grid>\n        <DockPanel DataContext=\"{Binding CustomOverlays, Source={StaticResource ServiceLocator}}\">\n            <DockPanel DockPanel.Dock=\"Top\">\n                <captura:ModernButton ToolTip=\"Add\"\n                                      Command=\"{Binding AddCommand}\"\n                                      IconData=\"{Binding Icons.Add, Source={StaticResource ServiceLocator}}\"/>\n                <Label Content=\"Add More\"/>\n            </DockPanel>\n\n            <ListView Margin=\"5\"\n                      ItemsSource=\"{Binding Collection}\"\n                      SelectedItem=\"{Binding SelectedItem, Mode=TwoWay}\">\n                <ListView.ItemTemplate>\n                    <DataTemplate>\n                        <TextBlock Text=\"Overlay\"/>\n                    </DataTemplate>\n                </ListView.ItemTemplate>\n            </ListView>\n\n            <GridSplitter Width=\"1\"/>\n\n            <DockPanel Visibility=\"{Binding SelectedItem, Converter={StaticResource NotNullConverter}}\"\n                       Margin=\"10\"\n                       VerticalAlignment=\"Top\">\n                <captura:TextOverlaySettingsControl Margin=\"0,5\"\n                                                    DataContext=\"{Binding SelectedItem}\"\n                                                    DockPanel.Dock=\"Bottom\"/>\n\n                <DockPanel DockPanel.Dock=\"Top\">\n                    <captura:ModernButton ToolTip=\"Remove\"\n                                          Command=\"{Binding RemoveCommand}\"\n                                          CommandParameter=\"{Binding SelectedItem}\"\n                                          IconData=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"\n                                          DockPanel.Dock=\"Right\"/>\n\n                    <CheckBox IsChecked=\"{Binding SelectedItem.Display, Mode=TwoWay}\"\n                              Content=\"Display\"/>\n                </DockPanel>\n\n                <Label Content=\"Text\"\n                       ContentStringFormat=\"{}{0}: \"/>\n\n                <TextBox Text=\"{Binding SelectedItem.Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"\n                         Margin=\"5,0\"/>\n            </DockPanel>\n        </DockPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/TextOverlaysPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class TextOverlaysPage\n    {\n        public TextOverlaysPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/TrayIconPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.TrayIconPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:hotkeys=\"clr-namespace:Captura.Hotkeys;assembly=Captura.Hotkeys\"\n      Title=\"{Binding TrayIcon, Source={StaticResource Loc}, Mode=OneWay}\"\n      DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\">\n    <Grid Margin=\"10\">\n        <StackPanel>\n            <CheckBox IsChecked=\"{Binding Settings.Tray.MinToTrayOnStartup}\"\n                      Margin=\"0,2\">\n                <TextBlock TextWrapping=\"Wrap\"\n                           Text=\"{Binding MinTrayStartup, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </CheckBox>\n\n            <CheckBox IsChecked=\"{Binding Settings.Tray.MinToTrayOnClose}\"\n                      Margin=\"0,2\">\n                <TextBlock TextWrapping=\"Wrap\"\n                           Text=\"{Binding MinTrayClose, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </CheckBox>\n\n            <CheckBox IsChecked=\"{Binding Settings.Tray.MinToTrayOnCaptureStart}\"\n                      Margin=\"0,2\">\n                <TextBlock TextWrapping=\"Wrap\"\n                           Text=\"{Binding MinToTrayOnCaptureStart, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </CheckBox>\n\n            <CheckBox IsChecked=\"{Binding Settings.Tray.ShowNotifications}\"\n                      Margin=\"0,2\">\n                <TextBlock TextWrapping=\"Wrap\"\n                           Text=\"{Binding ShowSysNotify, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </CheckBox>\n\n            <DockPanel Margin=\"0,10\">\n                <Label Content=\"Left Click Action\"\n                       Margin=\"0,0,10,0\"/>\n\n                <ComboBox SelectedValue=\"{Binding Settings.Tray.LeftClickAction, Mode=TwoWay}\"\n                          SelectedValuePath=\"ServiceName\"\n                          DisplayMemberPath=\"Description\"\n                          ItemsSource=\"{x:Static hotkeys:HotKeyManager.AllServices}\"/>\n            </DockPanel>\n        </StackPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/TrayIconPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class TrayIconPage\n    {\n        public TrayIconPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/VideoPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.VideoPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n      Title=\"{Binding Video, Source={StaticResource Loc}, Mode=OneWay}\"\n      DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\">\n    <Grid Margin=\"5\">\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition/>\n            <ColumnDefinition Width=\"Auto\"/>\n            <ColumnDefinition/>\n        </Grid.ColumnDefinitions>\n        <StackPanel>\n            <StackPanel Margin=\"0,5\">\n                <StackPanel.Resources>\n                    <Style TargetType=\"Path\" BasedOn=\"{StaticResource {x:Type Path}}\">\n                        <Setter Property=\"LayoutTransform\">\n                            <Setter.Value>\n                                <ScaleTransform ScaleX=\"0.6\" ScaleY=\"0.6\"/>\n                            </Setter.Value>\n                        </Setter>\n                        <Setter Property=\"Margin\" Value=\"0,0,5,0\"/>\n                        <Setter Property=\"VerticalAlignment\" Value=\"Center\"/>\n                    </Style>\n                    <Style TargetType=\"CheckBox\" BasedOn=\"{StaticResource {x:Type CheckBox}}\">\n                        <Setter Property=\"Margin\" Value=\"0,2\"/>\n                    </Style>\n                </StackPanel.Resources>\n                <CheckBox IsChecked=\"{Binding Settings.IncludeCursor}\"\n                          IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n                    <StackPanel Orientation=\"Horizontal\">\n                        <Path Data=\"{Binding Icons.Cursor, Source={StaticResource ServiceLocator}}\"/>\n                        <TextBlock Text=\"{Binding IncludeCursor, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                    </StackPanel>\n                </CheckBox>\n\n                <CheckBox IsChecked=\"{Binding Settings.Clicks.Display}\"\n                          IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                          ToolTip=\"Color, Opacity, Border can be configured at Settings / Overlays.\">\n                    <StackPanel Orientation=\"Horizontal\">\n                        <Path Data=\"{Binding Icons.Hand, Source={StaticResource ServiceLocator}}\"/>\n                        <TextBlock Text=\"{Binding IncludeClicks, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                    </StackPanel>\n                </CheckBox>\n\n                <CheckBox IsChecked=\"{Binding Settings.Keystrokes.Display}\"\n                          IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                          ToolTip=\"Color, Opacity, Border can be configured at Settings / Overlays.\">\n                    <StackPanel Orientation=\"Horizontal\">\n                        <Path Data=\"{Binding Icons.Keyboard, Source={StaticResource ServiceLocator}}\"/>\n                        <TextBlock Text=\"{Binding IncludeKeys, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                    </StackPanel>\n                </CheckBox>\n\n                <CheckBox IsChecked=\"{Binding Settings.Elapsed.Display}\"\n                          IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                          ToolTip=\"Color, Opacity, Border can be configured at Settings / Overlays.\">\n                    <StackPanel Orientation=\"Horizontal\">\n                        <Path Data=\"{Binding Icons.Timer, Source={StaticResource ServiceLocator}}\"/>\n                        <TextBlock Text=\"Show Elapsed time Overlay\"/>\n                    </StackPanel>\n                </CheckBox>\n            </StackPanel>\n\n            <GridSplitter IsEnabled=\"False\"\n                          Height=\"1\"\n                          Margin=\"0,10\"/>\n\n            <Grid Margin=\"0,5\"\n                  IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"*\"/>\n                    <ColumnDefinition Width=\"Auto\"/>\n                </Grid.ColumnDefinitions>\n\n                <Label Content=\"{Binding FrameRate, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}:\"/>\n                <Label Content=\"{Binding Settings.Video.FrameRate}\"\n                       Margin=\"5,0\"\n                       MinWidth=\"15\"\n                       ContentStringFormat=\"{}{0:N0}\"\n                       HorizontalContentAlignment=\"Right\"\n                       Visibility=\"{Binding Settings.Video.FpsLimit, Converter={StaticResource BoolToVisibilityConverter}}\"\n                       Grid.Column=\"1\"/>\n\n                <Slider Minimum=\"1\"\n                        Maximum=\"30\"\n                        SelectionStart=\"18\"\n                        SelectionEnd=\"22\"\n                        IsSelectionRangeEnabled=\"True\"\n                        Value=\"{Binding Settings.Video.FrameRate}\"\n                        Interval=\"1\"\n                        Visibility=\"{Binding Settings.Video.FpsLimit, Converter={StaticResource BoolToVisibilityConverter}}\"\n                        Grid.Column=\"2\"/>\n                <xctk:IntegerUpDown Visibility=\"{Binding Settings.Video.FpsLimit, Converter={StaticResource NegatingConverter}}\"\n                                    Margin=\"10,0,0,0\"\n                                    Minimum=\"1\"\n                                    Maximum=\"120\"\n                                    Value=\"{Binding Settings.Video.FrameRate}\"\n                                    Grid.Column=\"2\"/>\n\n                <CheckBox IsChecked=\"{Binding Settings.Video.FpsLimit}\"\n                          Content=\"Limit\"\n                          Margin=\"5,0,0,0\"\n                          Grid.Column=\"3\">\n                    <CheckBox.ToolTip>\n                        <TextBlock MaxWidth=\"300\"\n                                   TextWrapping=\"Wrap\">\n                            This Limit option is to prevent system crashes due to using high FPS on full screen or large region sizes.\n                        </TextBlock>\n                    </CheckBox.ToolTip>\n                </CheckBox>\n            </Grid>\n\n            <Grid Margin=\"0,0,0,5\"\n                  IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"*\"/>\n                </Grid.ColumnDefinitions>\n                <Grid.RowDefinitions>\n                    <RowDefinition/>\n                    <RowDefinition/>\n                </Grid.RowDefinitions>\n\n                <Label Content=\"{Binding PreStartCountdown, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Margin=\"0,2,10,2\"/>\n\n                <xctk:IntegerUpDown Value=\"{Binding Settings.PreStartCountdown, Mode=TwoWay}\"\n                                    Grid.Column=\"1\"\n                                    Margin=\"0,2\"/>\n\n                <Label Content=\"{Binding CaptureDuration, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Margin=\"0,2,10,2\"\n                       Grid.Row=\"1\"/>\n\n                <xctk:IntegerUpDown Value=\"{Binding Settings.Duration, Mode=TwoWay}\"\n                                    Grid.Row=\"1\"\n                                    Grid.Column=\"1\"\n                                    Margin=\"0,2\"\n                                    ToolTip=\"No of seconds after which recording is stopped automatically. 0 = don't stop automatically\"/>\n            </Grid>\n\n            <CheckBox IsChecked=\"{Binding Settings.CopyOutPathToClipboard}\"\n                      Margin=\"0,2\">\n                <TextBlock TextWrapping=\"Wrap\"\n                           Text=\"{Binding CopyOutPathClipboard, Source={StaticResource Loc}, Mode=OneWay}\"/>\n            </CheckBox>\n\n            <GridSplitter IsEnabled=\"False\"\n                          Height=\"1\"\n                          Margin=\"0,10\"/>\n\n            <CheckBox IsChecked=\"{Binding Settings.WindowsSettings.UseGdi}\"\n                      Margin=\"0,2\">\n                <TextBlock TextWrapping=\"Wrap\">\n                    Use GDI instead of DesktopDuplication <LineBreak/>\n                    <Run Text=\"(Requires App Restart)\"\n                         FontSize=\"10\"\n                         FontWeight=\"Light\"/>\n                </TextBlock>\n            </CheckBox>\n        </StackPanel>\n        <GridSplitter Grid.Column=\"1\"\n                      Width=\"1\"\n                      Margin=\"7,0\"/>\n        <StackPanel Grid.Column=\"2\">\n            <Label Content=\"Recorder Mode\"\n                   FontWeight=\"Bold\"\n                   Margin=\"0,5\"/>\n\n            <ListView Margin=\"0,5\"\n                      ItemsSource=\"{Binding VideoWritersViewModel.AvailableRecorderModes, Source={StaticResource ServiceLocator}}\"\n                      SelectedValue=\"{Binding Settings.Video.RecorderMode, Mode=TwoWay}\"\n                      IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                      BorderThickness=\"0.4\"\n                      SelectionMode=\"Single\">\n                <ListView.ItemsPanel>\n                    <ItemsPanelTemplate>\n                        <UniformGrid Rows=\"1\"/>\n                    </ItemsPanelTemplate>\n                </ListView.ItemsPanel>\n                <ListView.ItemContainerStyle>\n                    <Style TargetType=\"ListViewItem\" BasedOn=\"{StaticResource {x:Type ListViewItem}}\">\n                        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n                    </Style>\n                </ListView.ItemContainerStyle>\n            </ListView>\n\n            <DockPanel Margin=\"0,5\"\n                       IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                       Visibility=\"{Binding ViewConditions.IsReplayMode.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\">\n                <Label Content=\"Replay Duration\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Margin=\"0,2,10,2\"/>\n\n                <xctk:IntegerUpDown Value=\"{Binding Settings.Video.ReplayDuration, Mode=TwoWay}\"\n                                    Margin=\"0,2\"/>\n            </DockPanel>\n\n            <StackPanel Visibility=\"{Binding ViewConditions.IsStepsMode.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\">\n                <Label Content=\"Output type\"\n                       FontWeight=\"Bold\"/>\n\n                <ListView BorderThickness=\"0.4\"\n                          SelectionMode=\"Single\"                          \n                          Margin=\"0,5\"\n                          ItemsSource=\"{Binding VideoWritersViewModel.AvailableStepWriters, Source={StaticResource ServiceLocator}}\"\n                          SelectedValue=\"{Binding VideoWritersViewModel.SelectedStepsWriter, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                          IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\">\n                    <ListView.ItemsPanel>\n                        <ItemsPanelTemplate>\n                            <UniformGrid Rows=\"1\"/>\n                        </ItemsPanelTemplate>\n                    </ListView.ItemsPanel>\n                    <ListView.ItemContainerStyle>\n                        <Style TargetType=\"ListViewItem\" BasedOn=\"{StaticResource {x:Type ListViewItem}}\">\n                            <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>\n                        </Style>\n                    </ListView.ItemContainerStyle>\n                </ListView>\n\n                <CheckBox Content=\"Include Scrolls\"\n                          IsChecked=\"{Binding Settings.Steps.IncludeScrolls}\"\n                          Margin=\"0,5\"/>\n            </StackPanel>\n\n            <GridSplitter IsEnabled=\"False\"\n                          Height=\"1\"\n                          Margin=\"0,10\"/>\n\n            <Label Content=\"{Binding VideoEncoder, Source={StaticResource Loc}, Mode=OneWay}\"\n                   FontWeight=\"Bold\"\n                   Margin=\"0,5\"/>\n\n            <ListView Margin=\"0,5\"\n                      ItemsSource=\"{Binding VideoWritersViewModel.VideoWriterProviders, Source={StaticResource ServiceLocator}}\"\n                      SelectedValue=\"{Binding VideoWritersViewModel.SelectedVideoWriterKind, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                      IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                      BorderThickness=\"0.4\"\n                      SelectionMode=\"Single\">\n                <ListView.ItemsPanel>\n                    <ItemsPanelTemplate>\n                        <StackPanel Orientation=\"Horizontal\"/>\n                    </ItemsPanelTemplate>\n                </ListView.ItemsPanel>\n                <ListView.ItemTemplate>\n                    <DataTemplate>\n                        <Grid Background=\"#01000000\"\n                              MinWidth=\"60\">\n                            <Grid.ToolTip>\n                                <StackPanel MinWidth=\"200\">\n                                    <TextBlock Text=\"{Binding Name, Mode=OneWay}\"\n                                               FontWeight=\"Bold\"/>\n\n                                    <TextBlock Text=\"{Binding Description, Mode=OneWay}\"/>\n                                </StackPanel>\n                            </Grid.ToolTip>\n\n                            <TextBlock Text=\"{Binding Name, Mode=OneWay}\"\n                                       HorizontalAlignment=\"Center\"/>\n                        </Grid>\n                    </DataTemplate>\n                </ListView.ItemTemplate>\n            </ListView>\n\n            <DockPanel VerticalAlignment=\"Center\"\n                       Margin=\"0,5\"\n                       Visibility=\"{Binding ViewConditions.MultipleVideoWriters.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\">\n                <Button DockPanel.Dock=\"Right\"\n                        Margin=\"5,0,0,0\"\n                        Visibility=\"{Binding ViewConditions.IsFFmpeg.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\"\n                        Content=\"{Binding FFmpegLog, Source={StaticResource Loc}}\"\n                        Command=\"GoToPage\"\n                        CommandParameter=\"/Pages/FFmpegLogsPage.xaml\"\n                        Padding=\"10,0\"/>\n\n                <ComboBox ItemsSource=\"{Binding VideoWritersViewModel.AvailableVideoWriters, Source={StaticResource ServiceLocator}}\" \n                          SelectedValue=\"{Binding VideoWritersViewModel.SelectedVideoWriter, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                          IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                          Name=\"VideoWriterComboBox\">\n                    <ComboBox.ToolTip>\n                        <StackPanel MinWidth=\"200\">\n                            <Label Content=\"{Binding VideoWritersViewModel.SelectedVideoWriter, Mode=OneWay, Source={StaticResource ServiceLocator}}\"\n                                   FontWeight=\"Bold\"/>\n\n                            <Label Content=\"{Binding VideoWritersViewModel.SelectedVideoWriter.Extension, Mode=OneWay, Source={StaticResource ServiceLocator}}\"\n                                   ContentStringFormat=\"{}File extension: {0}\"/>\n\n                            <TextBlock Text=\"{Binding VideoWritersViewModel.SelectedVideoWriter.Description, Mode=OneWay, Source={StaticResource ServiceLocator}}\"\n                                       Visibility=\"{Binding VideoWritersViewModel.SelectedVideoWriter.Description, Converter={StaticResource NotNullConverter}, Source={StaticResource ServiceLocator}}\"/>\n                        </StackPanel>\n                    </ComboBox.ToolTip>\n                </ComboBox>\n            </DockPanel>\n\n            <DockPanel Margin=\"0,5\"\n                       IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                       Visibility=\"{Binding ViewConditions.IsVideoQuality.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\">\n                <Label Content=\"{Binding Quality, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}:\"/>\n                <Label Content=\"{Binding Settings.Video.Quality}\"\n                       ContentStringFormat=\"{}{0:N0}%\"\n                       Margin=\"5,0\"\n                       MinWidth=\"30\"\n                       HorizontalContentAlignment=\"Right\"/>\n                <Slider Minimum=\"1\" \n                        Maximum=\"100\"\n                        SelectionStart=\"60\"\n                        SelectionEnd=\"80\"\n                        IsSelectionRangeEnabled=\"True\"\n                        Value=\"{Binding Settings.Video.Quality}\"/>\n            </DockPanel>\n\n            <CheckBox Margin=\"0,15,0,5\"\n                      Content=\"Convert after encoding\"\n                      IsChecked=\"{Binding Settings.Video.PostConvert}\"\n                      IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"/>\n\n            <ComboBox ItemsSource=\"{Binding VideoWritersViewModel.AvailablePostWriters, Source={StaticResource ServiceLocator}}\" \n                      SelectedValue=\"{Binding VideoWritersViewModel.SelectedPostWriter, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                      IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                      Visibility=\"{Binding Settings.Video.PostConvert, Converter={StaticResource BoolToVisibilityConverter}}\"\n                      DisplayMemberPath=\"Name\"\n                      Margin=\"0,5\"/>\n        </StackPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/VideoPage.xaml.cs",
    "content": "﻿namespace Captura\n{\n    public partial class VideoPage\n    {\n        public VideoPage()\n        {\n            InitializeComponent();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Pages/WebcamPage.xaml",
    "content": "﻿<Page x:Class=\"Captura.WebcamPage\"\n      xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n      xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n      xmlns:captura=\"clr-namespace:Captura\"\n      Title=\"{Binding WebCam, Source={StaticResource Loc}, Mode=OneWay}\"\n      DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\">\n    <Grid Margin=\"5,0\">\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition Width=\"250\"/>\n            <ColumnDefinition Width=\"Auto\"/>\n            <ColumnDefinition Width=\"*\"/>\n        </Grid.ColumnDefinitions>\n        <StackPanel DataContext=\"{Binding Settings.WebcamOverlay}\">\n            <DockPanel>\n                <captura:ModernButton ToolTip=\"{Binding Refresh, Source={StaticResource Loc}, Mode=OneWay}\"\n                                      Command=\"{Binding WebcamModel.RefreshCommand, Source={StaticResource ServiceLocator}}\"\n                                      IconData=\"{Binding Icons.Refresh, Source={StaticResource ServiceLocator}}\"\n                                      DockPanel.Dock=\"Right\"/>\n\n                <captura:ModernButton ToolTip=\"Capture Image\"\n                                      Click=\"CaptureImage_OnClick\"\n                                      IconData=\"{Binding Icons.Camera, Source={StaticResource ServiceLocator}}\"\n                                      DockPanel.Dock=\"Right\"/>\n\n                <Path Data=\"{Binding Icons.Webcam, Source={StaticResource ServiceLocator}}\"\n                      Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"0,0,7,0\"\n                      Stretch=\"Uniform\"\n                      HorizontalAlignment=\"Center\"\n                      VerticalAlignment=\"Center\"\n                      ToolTip=\"{Binding WebCam, Source={StaticResource Loc}, Mode=OneWay}\"/>\n\n                <ComboBox ItemsSource=\"{Binding WebcamModel.AvailableCams, Source={StaticResource ServiceLocator}}\"\n                          SelectedItem=\"{Binding WebcamModel.SelectedCam, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n                          IsEnabled=\"{Binding ViewConditions.CanChangeWebcam.Value, Source={StaticResource ServiceLocator}}\"\n                          DisplayMemberPath=\"Name\"\n                          VerticalAlignment=\"Center\"\n                          Margin=\"0,0,7,0\"/>\n            </DockPanel>\n\n            <CheckBox IsChecked=\"{Binding SeparateFile}\"\n                      Content=\"{Binding WebCamSeparateFile, Source={StaticResource Loc}, Mode=OneWay}\"\n                      IsEnabled=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\"\n                      Visibility=\"{Binding ViewConditions.CanWebcamSeparateFile.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource BoolToVisibilityConverter}}\"\n                      Margin=\"0,5\"/>\n\n            <Grid Margin=\"0,15,0,5\">\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"*\"/>\n                </Grid.ColumnDefinitions>\n\n                <Path Data=\"{Binding Icons.Opacity, Source={StaticResource ServiceLocator}}\"\n                      Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"0,0,10,0\"\n                      Stretch=\"Uniform\"\n                      HorizontalAlignment=\"Center\"\n                      VerticalAlignment=\"Center\"/>\n\n                <Label Content=\"{Binding Opacity, Source={StaticResource Loc}, Mode=OneWay}\"\n                       ContentStringFormat=\"{}{0}: \"\n                       Grid.Column=\"1\"\n                       Margin=\"0,3\"/>\n\n                <Slider Grid.Column=\"2\"\n                        Minimum=\"1\"\n                        Maximum=\"100\"\n                        Value=\"{Binding Opacity, Mode=TwoWay}\"/>\n            </Grid>\n        </StackPanel>\n        <GridSplitter Grid.Column=\"1\"\n                      Width=\"1\"\n                      Margin=\"5,0\"/>\n        <DockPanel Grid.Column=\"2\"\n                   DataContext=\"{Binding Settings.WebcamOverlay}\">\n            <DockPanel Margin=\"5\"\n                       DockPanel.Dock=\"Top\">\n                <Label Content=\"Scale: \"/>\n                <Slider Value=\"{Binding Scale, Mode=TwoWay}\"\n                        TickPlacement=\"BottomRight\"\n                        TickFrequency=\"0.1\"\n                        Minimum=\"0\"\n                        Maximum=\"1\"/>\n            </DockPanel>\n\n            <DockPanel VerticalAlignment=\"Center\"\n                       HorizontalAlignment=\"Center\"\n                       Margin=\"0,0,0,10\">\n                <DockPanel DockPanel.Dock=\"Bottom\"\n                           Margin=\"5,5,40,5\">\n                    <Label Content=\"X\"\n                           Margin=\"0,0,5,0\"/>\n                    <Slider Value=\"{Binding XLoc, Mode=TwoWay}\"\n                            Minimum=\"0\"\n                            Maximum=\"1\"/>\n                </DockPanel>\n                <DockPanel DockPanel.Dock=\"Right\"\n                           Margin=\"5\">\n                    <Label Content=\"Y\"\n                           HorizontalContentAlignment=\"Center\"\n                           Margin=\"0,0,0,5\"\n                           DockPanel.Dock=\"Top\"/>\n                    <Slider Value=\"{Binding YLoc, Mode=TwoWay}\"\n                            Orientation=\"Vertical\"\n                            IsDirectionReversed=\"True\"\n                            Minimum=\"0\"\n                            Maximum=\"1\"/>\n                </DockPanel>\n                <Grid Name=\"PreviewGrid\"\n                      Background=\"DimGray\">\n                    <Image Name=\"Img\"\n                           Stretch=\"Uniform\"/>\n\n                    <!-- Invisible but still required to prevent render errors -->\n                    <Label Name=\"PreviewTarget\"\n                           HorizontalAlignment=\"Left\"\n                           VerticalAlignment=\"Top\"\n                           Background=\"#00FFFFFF\"\n                           MaxWidth=\"{Binding ActualWidth, ElementName=Img}\"\n                           MaxHeight=\"{Binding ActualHeight, ElementName=Img}\"/>\n                </Grid>\n            </DockPanel>\n        </DockPanel>\n    </Grid>\n</Page>\n"
  },
  {
    "path": "src/Captura/Pages/WebcamPage.xaml.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Reactive.Linq;\nusing WSize = System.Windows.Size;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Interop;\nusing Captura.ViewModels;\nusing Captura.Webcam;\nusing Captura.Windows.Gdi;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\nusing Xceed.Wpf.Toolkit.Core.Utilities;\n\nnamespace Captura\n{\n    public partial class WebcamPage\n    {\n        readonly WebcamModel _webcamModel;\n        readonly ScreenShotModel _screenShotModel;\n        readonly IPlatformServices _platformServices;\n        readonly WebcamOverlayReactor _reactor;\n\n        public WebcamPage(WebcamModel WebcamModel,\n            ScreenShotModel ScreenShotModel,\n            IPlatformServices PlatformServices,\n            WebcamOverlaySettings WebcamSettings)\n        {\n            _webcamModel = WebcamModel;\n            _screenShotModel = ScreenShotModel;\n            _platformServices = PlatformServices;\n\n            _reactor = new WebcamOverlayReactor(WebcamSettings);\n\n            Loaded += OnLoaded;\n\n            InitializeComponent();\n        }\n\n        bool _loaded;\n\n        async void OnLoaded(object Sender, RoutedEventArgs E)\n        {\n            await UpdateBackground();\n\n            if (_loaded)\n                return;\n\n            _loaded = true;\n\n            var control = PreviewTarget;\n\n            control.BindOne(MarginProperty,\n                _reactor.Location.Select(M => new Thickness(M.X, M.Y, 0, 0)).ToReadOnlyReactivePropertySlim());\n\n            control.BindOne(WidthProperty,\n                _reactor.Size.Select(M => M.Width).ToReadOnlyReactivePropertySlim());\n            control.BindOne(HeightProperty,\n                _reactor.Size.Select(M => M.Height).ToReadOnlyReactivePropertySlim());\n\n            control.BindOne(OpacityProperty, _reactor.Opacity);\n        }\n\n        async Task UpdateBackground()\n        {\n            Img.Source = await WpfExtensions.GetBackground();\n        }\n\n        IReadOnlyReactiveProperty<IWebcamCapture> _webcamCapture;\n\n        public void SetupPreview()\n        {\n            _webcamModel.PreviewClicked += SettingsWindow.ShowWebcamPage;\n\n            IsVisibleChanged += (S, E) =>\n            {\n                if (IsVisible && _webcamCapture == null)\n                {\n                    _webcamCapture = _webcamModel.InitCapture();\n\n                    if (_webcamCapture.Value is { } capture)\n                    {\n                        _reactor.WebcamSize.OnNext(new WSize(capture.Width, capture.Height));\n\n                        UpdateWebcamPreview();\n                    }\n                }\n                else if (!IsVisible && _webcamCapture != null)\n                {\n                    _webcamModel.ReleaseCapture();\n                    _webcamCapture = null;\n                }\n            };\n\n            void OnRegionChange()\n            {\n                if (!IsVisible)\n                    return;\n\n                _reactor.FrameSize.OnNext(new WSize(Img.ActualWidth, Img.ActualHeight));\n            }\n\n            PreviewGrid.LayoutUpdated += (S, E) => OnRegionChange();\n\n            _webcamModel\n                .ObserveProperty(M => M.SelectedCam)\n                .Subscribe(M => UpdateWebcamPreview());\n\n            _reactor.Location\n                .CombineLatest(_reactor.Size, (M, N) =>\n                {\n                    UpdateWebcamPreview();\n                    return 0;\n                })\n                .Subscribe();\n\n            UpdateWebcamPreview();\n        }\n\n        async void CaptureImage_OnClick(object Sender, RoutedEventArgs E)\n        {\n            try\n            {\n                var img = _webcamCapture.Value?.Capture(GraphicsBitmapLoader.Instance);\n\n                await _screenShotModel.SaveScreenShot(img);\n            }\n            catch { }\n        }\n\n        Rectangle GetPreviewWindowRect()\n        {\n            var parentWindow = VisualTreeHelperEx.FindAncestorByType<Window>(this);\n\n            var relativePt = PreviewGrid.TranslatePoint(new System.Windows.Point(0, 0), parentWindow);\n\n            var position = _reactor.Location.Value;\n            var size = _reactor.Size.Value;\n\n            var rect = new RectangleF((float)(relativePt.X + position.X),\n                (float)(relativePt.Y + position.Y),\n                (float)(size.Width),\n                (float)(size.Height));\n\n            return rect.ApplyDpi();\n        }\n\n        void UpdateWebcamPreview()\n        {\n            if (PresentationSource.FromVisual(this) is HwndSource source)\n            {\n                var win = _platformServices.GetWindow(source.Handle);\n\n                var rect = GetPreviewWindowRect();\n\n                _webcamCapture?.Value?.UpdatePreview(win, rect);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Presentation/CroppingAdorner.cs",
    "content": "﻿using System;\nusing System.Windows.Shapes;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Controls.Primitives;\nusing System.Windows.Documents;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Imaging;\nusing Point = System.Drawing.Point;\n\nnamespace Captura\n{\n    public class CroppingAdorner : Adorner\n    {\n        #region Private variables\n        // Width of the thumbs. I know these really aren't \"pixels\", but px is still a good mnemonic.\n        const int CpxThumbWidth = 6;\n\n        // PuncturedRect to hold the \"Cropping\" portion of the adorner\n        readonly PuncturedRect _prCropMask;\n\n        // Canvas to hold the thumbs so they can be moved in response to the user\n        readonly Canvas _cnvThumbs;\n\n        // Cropping adorner uses Thumbs for visual elements.  \n        // The Thumbs have built-in mouse input handling.\n        readonly CropThumb _crtTopLeft;\n\n        readonly CropThumb _crtTopRight;\n        readonly CropThumb _crtBottomLeft;\n        readonly CropThumb _crtBottomRight;\n\n        readonly CropThumb _crtTop;\n        readonly CropThumb _crtLeft;\n        readonly CropThumb _crtBottom;\n        readonly CropThumb _crtRight;\n\n        readonly Thumb _crtMove;\n\n        readonly Border _checkButton;\n\n        // To store and manage the adorner's visual children.\n        readonly VisualCollection _vc;\n        #endregion\n        \n        #region Routed Events\n        public static readonly RoutedEvent CropChangedEvent = EventManager.RegisterRoutedEvent(\n            nameof(CropChanged),\n            RoutingStrategy.Bubble,\n            typeof(RoutedEventHandler),\n            typeof(CroppingAdorner));\n\n        public event RoutedEventHandler CropChanged\n        {\n            add => AddHandler(CropChangedEvent, value);\n            remove => RemoveHandler(CropChangedEvent, value);\n        }\n\n        public event Action Checked;\n        #endregion\n\n        #region Dependency Properties\n        public static readonly DependencyProperty FillProperty = Shape.FillProperty.AddOwner(typeof(CroppingAdorner));\n\n        public Brush Fill\n        {\n            get => (Brush)GetValue(FillProperty);\n            set => SetValue(FillProperty, value);\n        }\n\n        static void FillPropChanged(DependencyObject D, DependencyPropertyChangedEventArgs Args)\n        {\n            if (D is CroppingAdorner crp)\n            {\n                crp._prCropMask.Fill = (Brush)Args.NewValue;\n            }\n        }\n        #endregion\n\n        #region Constructor\n        static CroppingAdorner()\n        {\n            var clr = Colors.Red;\n            \n            clr.A = 80;\n            FillProperty.OverrideMetadata(typeof(CroppingAdorner),\n                new PropertyMetadata(\n                    new SolidColorBrush(clr),\n                    FillPropChanged));\n        }\n\n        public CroppingAdorner(UIElement AdornedElement, Rect RectInit)\n            : base(AdornedElement)\n        {\n            _vc = new VisualCollection(this);\n            _prCropMask = new PuncturedRect\n            {\n                IsHitTestVisible = false,\n                RectInterior = RectInit,\n                Fill = Fill\n            };\n            _vc.Add(_prCropMask);\n            _cnvThumbs = new Canvas\n            {\n                HorizontalAlignment = HorizontalAlignment.Stretch,\n                VerticalAlignment = VerticalAlignment.Stretch\n            };\n\n            _vc.Add(_cnvThumbs);\n            \n            _crtMove = new Thumb\n            {\n                Cursor = Cursors.Hand,\n                Opacity = 0\n            };\n\n            _cnvThumbs.Children.Add(_crtMove);\n\n            BuildCorner(ref _crtTop, Cursors.SizeNS);\n            BuildCorner(ref _crtBottom, Cursors.SizeNS);\n            BuildCorner(ref _crtLeft, Cursors.SizeWE);\n            BuildCorner(ref _crtRight, Cursors.SizeWE);\n            BuildCorner(ref _crtTopLeft, Cursors.SizeNWSE);\n            BuildCorner(ref _crtTopRight, Cursors.SizeNESW);\n            BuildCorner(ref _crtBottomLeft, Cursors.SizeNESW);\n            BuildCorner(ref _crtBottomRight, Cursors.SizeNWSE);\n\n            var btn = new ModernButton\n            {\n                IconData = Geometry.Parse(ServiceProvider.Get<IIconSet>().Check),\n                Cursor = Cursors.Hand,\n                Foreground = new SolidColorBrush(Colors.White)\n            };\n\n            _checkButton = new Border\n            {\n                CornerRadius = new CornerRadius(20),\n                VerticalAlignment = VerticalAlignment.Top,\n                HorizontalAlignment = HorizontalAlignment.Left,\n                Background = new SolidColorBrush(Colors.LimeGreen),\n                BorderBrush = new SolidColorBrush(Colors.Black),\n                BorderThickness = new Thickness(0.3),\n                Child = btn\n            };\n\n            _cnvThumbs.Children.Add(_checkButton);\n\n            btn.Click += (S, E) => Checked?.Invoke();\n            \n            // Add handlers for Cropping.\n            _crtBottomLeft.DragDelta += (S, E) => HandleDrag(S, E, 1, 0, -1, 1);\n            _crtBottomRight.DragDelta += (S, E) => HandleDrag(S, E, 0, 0, 1, 1);\n            _crtTopLeft.DragDelta += (S, E) => HandleDrag(S, E, 1, 1, -1, -1);\n            _crtTopRight.DragDelta += (S, E) => HandleDrag(S, E, 0, 1, 1, -1);\n            _crtTop.DragDelta += (S, E) => HandleDrag(S, E, 0, 1, 0, -1);\n            _crtBottom.DragDelta += (S, E) => HandleDrag(S, E, 0, 0, 0, 1);\n            _crtRight.DragDelta += (S, E) => HandleDrag(S, E, 0, 0, 1, 0);\n            _crtLeft.DragDelta += (S, E) => HandleDrag(S, E, 1, 0, -1, 0);\n\n            _crtMove.DragDelta += HandleMove;\n\n            // We have to keep the clipping interior within the bounds of the adorned element\n            // so we have to track it's size to guarantee that...\n\n            if (AdornedElement is FrameworkElement fel)\n            {\n                fel.SizeChanged += AdornedElement_SizeChanged;\n            }\n        }\n        #endregion\n\n        #region Thumb handlers\n        // Generic handler for Cropping\n        void HandleThumb(\n            double DeltaRatioLeft,\n            double DeltaRatioTop,\n            double DeltaRatioWidth,\n            double DeltaRatioHeight,\n            double DeltaX,\n            double DeltaY)\n        {\n            var rcInterior = _prCropMask.RectInterior;\n\n            if (rcInterior.Width + DeltaRatioWidth * DeltaX < 0)\n            {\n                DeltaX = -rcInterior.Width / DeltaRatioWidth;\n            }\n\n            if (rcInterior.Height + DeltaRatioHeight * DeltaY < 0)\n            {\n                DeltaY = -rcInterior.Height / DeltaRatioHeight;\n            }\n\n            rcInterior = new Rect(\n                rcInterior.Left + DeltaRatioLeft * DeltaX,\n                rcInterior.Top + DeltaRatioTop * DeltaY,\n                rcInterior.Width + DeltaRatioWidth * DeltaX,\n                rcInterior.Height + DeltaRatioHeight * DeltaY);\n\n            _prCropMask.RectInterior = rcInterior;\n            SetThumbs(_prCropMask.RectInterior);\n            RaiseEvent(new RoutedEventArgs(CropChangedEvent, this));\n        }\n\n        void HandleMove(object Sender, DragDeltaEventArgs Args)\n        {\n            if (AdornedElement is FrameworkElement fel)\n            {\n                var rcInterior = _prCropMask.RectInterior;\n\n                var left = rcInterior.Left + Args.HorizontalChange;\n                var top = rcInterior.Top + Args.VerticalChange;\n\n                if (left < 0)\n                    left = 0;\n\n                if (left + rcInterior.Width > fel.ActualWidth)\n                    left = fel.ActualWidth - rcInterior.Width;\n\n                if (top < 0)\n                    top = 0;\n\n                if (top + rcInterior.Height > fel.ActualHeight)\n                    top = fel.ActualHeight - rcInterior.Height;\n\n                rcInterior = new Rect(left, top, rcInterior.Width, rcInterior.Height);\n\n                _prCropMask.RectInterior = rcInterior;\n\n                SetThumbs(_prCropMask.RectInterior);\n\n                RaiseEvent(new RoutedEventArgs(CropChangedEvent, this));\n            }\n        }\n\n        void HandleDrag(object Sender, DragDeltaEventArgs Args, int L, int T, int W, int H)\n        {\n            if (Sender is CropThumb)\n            {\n                HandleThumb(L, T, W, H, Args.HorizontalChange, Args.VerticalChange);\n            }\n        }\n        #endregion\n        \n        void AdornedElement_SizeChanged(object Sender, SizeChangedEventArgs E)\n        {\n            var ratio = E.NewSize.Width / E.PreviousSize.Width;\n\n            var rcInterior = _prCropMask.RectInterior;\n            \n            double intLeft = rcInterior.Left * ratio,\n                intTop = rcInterior.Top * ratio,\n                intWidth = rcInterior.Width * ratio,\n                intHeight = rcInterior.Height * ratio;\n            \n            _prCropMask.RectInterior = new Rect(intLeft, intTop, intWidth, intHeight);\n        }\n        \n        #region Arranging/positioning\n        void SetThumbs(Rect Rect)\n        {\n            _crtBottomRight.SetPos(Rect.Right, Rect.Bottom);\n            _crtTopLeft.SetPos(Rect.Left, Rect.Top);\n            _crtTopRight.SetPos(Rect.Right, Rect.Top);\n            _crtBottomLeft.SetPos(Rect.Left, Rect.Bottom);\n            _crtTop.SetPos(Rect.Left + Rect.Width / 2, Rect.Top);\n            _crtBottom.SetPos(Rect.Left + Rect.Width / 2, Rect.Bottom);\n            _crtLeft.SetPos(Rect.Left, Rect.Top + Rect.Height / 2);\n            _crtRight.SetPos(Rect.Right, Rect.Top + Rect.Height / 2);\n\n            _crtMove.Width = Rect.Width;\n            _crtMove.Height = Rect.Height;\n            Canvas.SetLeft(_crtMove, Rect.Left);\n            Canvas.SetTop(_crtMove, Rect.Top);\n\n            Canvas.SetLeft(_checkButton, Rect.Right - _checkButton.ActualWidth - 15);\n            Canvas.SetTop(_checkButton, Rect.Bottom - _checkButton.ActualHeight - 10);\n        }\n\n        // Arrange the Adorners.\n        protected override Size ArrangeOverride(Size FinalSize)\n        {\n            var rcExterior = new Rect(0, 0, AdornedElement.RenderSize.Width, AdornedElement.RenderSize.Height);\n            _prCropMask.RectExterior = rcExterior;\n            var rcInterior = _prCropMask.RectInterior;\n            _prCropMask.Arrange(rcExterior);\n\n            SetThumbs(rcInterior);\n            _cnvThumbs.Arrange(rcExterior);\n\n            return FinalSize;\n        }\n        #endregion\n\n        public Rect SelectedRegion => _prCropMask.RectInterior;\n\n        public BitmapSource BpsCrop(BitmapSource Bmp)\n        {\n            var ratio = Bmp.PixelWidth / AdornedElement.RenderSize.Width;\n\n            var rcInterior = _prCropMask.RectInterior;\n\n            Point ToPoint(double X, double Y)\n            {\n                return new Point((int)(X * ratio), (int)(Y * ratio));\n            }\n\n            var pxFromSize = ToPoint(rcInterior.Width, rcInterior.Height);\n            \n            var pxFromPos = ToPoint(rcInterior.Left, rcInterior.Top);\n            var pxWhole = ToPoint(AdornedElement.RenderSize.Width, AdornedElement.RenderSize.Height);\n\n            pxFromSize.X = Math.Max(Math.Min(pxWhole.X - pxFromPos.X, pxFromSize.X), 0);\n            pxFromSize.Y = Math.Max(Math.Min(pxWhole.Y - pxFromPos.Y, pxFromSize.Y), 0);\n\n            if (pxFromSize.X == 0 || pxFromSize.Y == 0)\n            {\n                return null;\n            }\n\n            var rcFrom = new Int32Rect(pxFromPos.X, pxFromPos.Y, pxFromSize.X, pxFromSize.Y);\n\n            return new CroppedBitmap(Bmp, rcFrom);\n        }\n        \n        void BuildCorner(ref CropThumb Thumb, Cursor CustomCursor)\n        {\n            if (Thumb != null)\n                return;\n\n            Thumb = new CropThumb(CpxThumbWidth)\n            {\n                Cursor = CustomCursor\n            };\n\n            _cnvThumbs.Children.Add(Thumb);\n        }\n\n        #region Visual tree overrides\n        // Override the VisualChildrenCount and GetVisualChild properties to interface with \n        // the adorner's visual collection.\n        protected override int VisualChildrenCount => _vc.Count;\n\n        protected override Visual GetVisualChild(int Index) => _vc[Index];\n        #endregion\n        \n        class CropThumb : Thumb\n        {\n            readonly int _width;\n\n            public CropThumb(int Width)\n            {\n                _width = Width;\n            }\n            \n            protected override Visual GetVisualChild(int Index) => null;\n\n            protected override void OnRender(DrawingContext DrawingContext)\n            {\n                DrawingContext.DrawRoundedRectangle(Brushes.White, new Pen(Brushes.Black, 1), new Rect(new Size(_width, _width)), 1, 1);\n            }\n\n            public void SetPos(double X, double Y)\n            {\n                Canvas.SetTop(this, Y - _width / 2.0);\n                Canvas.SetLeft(this, X - _width / 2.0);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Presentation/OverlayPositionAdorner.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Windows.Controls.Primitives;\nusing System.Windows.Documents;\nusing System.Windows.Input;\nusing System.Windows.Media;\n\nnamespace Captura\n{\n    public class OverlayPositionAdorner : Adorner\n    {\n        #region Thumbs\n        readonly Thumb _topLeft;\n        readonly Thumb _topRight;\n        readonly Thumb _bottomLeft;\n        readonly Thumb _bottomRight;\n\n        readonly Thumb _top;\n        readonly Thumb _left;\n        readonly Thumb _right;\n        readonly Thumb _bottom;\n\n        readonly Thumb _center;\n        #endregion\n\n        readonly bool _canResize;\n\n        readonly VisualCollection _visualChildren;\n\n        public OverlayPositionAdorner(UIElement Element, bool CanResize = true) : base(Element)\n        {\n            _canResize = CanResize;\n\n            _visualChildren = new VisualCollection(this);\n\n            BuildAdornerThumb(ref _center, Cursors.Hand);\n            _center.Opacity = 0;\n\n            _center.DragDelta += (S, E) => HandleDrag(HitType.Body, E);\n\n            if (CanResize)\n            {\n                BuildAdornerThumb(ref _topLeft, Cursors.SizeNWSE);\n                BuildAdornerThumb(ref _topRight, Cursors.SizeNESW);\n                BuildAdornerThumb(ref _bottomLeft, Cursors.SizeNESW);\n                BuildAdornerThumb(ref _bottomRight, Cursors.SizeNWSE);\n\n                BuildAdornerThumb(ref _top, Cursors.SizeNS);\n                BuildAdornerThumb(ref _left, Cursors.SizeWE);\n                BuildAdornerThumb(ref _right, Cursors.SizeWE);\n                BuildAdornerThumb(ref _bottom, Cursors.SizeNS);\n\n                _topLeft.DragDelta += (S, E) => HandleDrag(HitType.UpperLeft, E);\n                _topRight.DragDelta += (S, E) => HandleDrag(HitType.UpperRight, E);\n                _bottomLeft.DragDelta += (S, E) => HandleDrag(HitType.LowerLeft, E);\n                _bottomRight.DragDelta += (S, E) => HandleDrag(HitType.LowerRight, E);\n\n                _top.DragDelta += (S, E) => HandleDrag(HitType.Top, E);\n                _left.DragDelta += (S, E) => HandleDrag(HitType.Left, E);\n                _right.DragDelta += (S, E) => HandleDrag(HitType.Right, E);\n                _bottom.DragDelta += (S, E) => HandleDrag(HitType.Bottom, E);\n            }\n\n            Opacity = 0.01;\n\n            MouseEnter += (S, E) => Opacity = 1;\n            MouseLeave += (S, E) => Opacity = 0.01;\n        }\n\n        void HandleDrag(HitType MouseHitType, DragDeltaEventArgs Args)\n        {\n            if (!(AdornedElement is FrameworkElement fel))\n                return;\n\n            var offsetX = (int) Args.HorizontalChange;\n            var offsetY = (int) Args.VerticalChange;\n\n            var har = fel.HorizontalAlignment == HorizontalAlignment.Right;\n            var vab = fel.VerticalAlignment == VerticalAlignment.Bottom;\n\n            var newX = (int)(har ? fel.Margin.Right : fel.Margin.Left);\n            var newY = (int)(vab ? fel.Margin.Bottom : fel.Margin.Top);\n            var newWidth = (int) fel.ActualWidth;\n            var newHeight = (int) fel.ActualHeight;\n\n            void ModifyX(bool Possitive)\n            {\n                if (Possitive)\n                    newX += offsetX;\n                else newX -= offsetX;\n            }\n\n            void ModifyY(bool Possitive)\n            {\n                if (Possitive)\n                    newY += offsetY;\n                else newY -= offsetY;\n            }\n\n            void ModifyWidth(bool Possitive)\n            {\n                if (Possitive)\n                    newWidth += offsetX;\n                else newWidth -= offsetX;\n            }\n\n            void ModifyHeight(bool Possitive)\n            {\n                if (Possitive)\n                    newHeight += offsetY;\n                else newHeight -= offsetY;\n            }\n\n            switch (MouseHitType)\n            {\n                case HitType.Body:\n                    ModifyX(!har);\n                    ModifyY(!vab);\n                    break;\n\n                case HitType.UpperLeft:\n                    if (har)\n                    {\n                        ModifyWidth(false);\n                    }\n                    else\n                    {\n                        ModifyX(true);\n                        ModifyWidth(false);\n                    }\n\n                    if (vab)\n                    {\n                        ModifyHeight(false);\n                    }\n                    else\n                    {\n                        ModifyY(true);\n                        ModifyHeight(false);\n                    }\n                    break;\n\n                case HitType.UpperRight:\n                    if (har)\n                    {\n                        ModifyX(false);\n                        ModifyWidth(true);\n                    }\n                    else ModifyWidth(true);\n\n                    if (vab)\n                    {\n                        ModifyHeight(false);\n                    }\n                    else\n                    {\n                        ModifyY(true);\n                        ModifyHeight(false);\n                    }\n                    break;\n\n                case HitType.LowerRight:\n                    if (har)\n                    {\n                        ModifyX(false);\n                        ModifyWidth(true);\n                    }\n                    else ModifyWidth(true);\n\n                    if (vab)\n                    {\n                        ModifyY(false);\n                        ModifyHeight(true);\n                    }\n                    else ModifyHeight(true);\n                    break;\n\n                case HitType.LowerLeft:\n                    if (har)\n                    {\n                        ModifyWidth(false);\n                    }\n                    else\n                    {\n                        ModifyX(true);\n                        ModifyWidth(false);\n                    }\n\n                    if (vab)\n                    {\n                        ModifyY(false);\n                        ModifyHeight(true);\n                    }\n                    else ModifyHeight(true);\n                    break;\n\n                case HitType.Left:\n                    if (har)\n                    {\n                        ModifyWidth(false);\n                    }\n                    else\n                    {\n                        ModifyX(true);\n                        ModifyWidth(false);\n                    }\n                    break;\n\n                case HitType.Right:\n                    if (har)\n                    {\n                        ModifyX(false);\n                        ModifyWidth(true);\n                    }\n                    else ModifyWidth(true);\n                    break;\n\n                case HitType.Bottom:\n                    if (vab)\n                    {\n                        ModifyY(false);\n                        ModifyHeight(true);\n                    }\n                    else ModifyHeight(true);\n                    break;\n\n                case HitType.Top:\n                    if (vab)\n                    {\n                        ModifyHeight(false);\n                    }\n                    else\n                    {\n                        ModifyY(true);\n                        ModifyHeight(false);\n                    }\n                    break;\n            }\n\n            if (newWidth > 0 && newHeight > 0)\n            {\n                if (newX < 0)\n                {\n                    newX = 0;\n                }\n\n                if (newY < 0)\n                {\n                    newY = 0;\n                }\n\n                double left = 0, top = 0, right = 0, bottom = 0;\n\n                if (har)\n                    right = newX;\n                else left = newX;\n\n                if (vab)\n                    bottom = newY;\n                else top = newY;\n\n                fel.Margin = new Thickness(left, top, right, bottom);\n\n                PositionUpdated?.Invoke(new Rect(newX, newY, newWidth, newHeight));\n\n                if (MouseHitType != HitType.Body)\n                {\n                    fel.Width = newWidth;\n                    fel.Height = newHeight;\n                }\n            }\n        }\n\n        public event Action<Rect> PositionUpdated;\n        \n        void BuildAdornerThumb(ref Thumb CornerThumb, Cursor CustomizedCursors)\n        {\n            if (CornerThumb != null)\n                return;\n\n            CornerThumb = new Thumb\n            {\n                Cursor = CustomizedCursors,\n                Height = 10,\n                Width = 10,\n                Opacity = 0.5,\n                Background = new SolidColorBrush(Colors.Red)\n            };\n\n            _visualChildren.Add(CornerThumb);\n        }\n\n        protected override Size ArrangeOverride(Size FinalSize)\n        {\n            base.ArrangeOverride(FinalSize);\n\n            var desireWidth = AdornedElement.RenderSize.Width;\n            var desireHeight = AdornedElement.RenderSize.Height;\n\n            var adornerWidth = DesiredSize.Width;\n            var adornerHeight = DesiredSize.Height;\n\n            _center.Height = desireHeight;\n            _center.Width = desireWidth;\n            _center.Arrange(new Rect(0, 0, desireWidth, desireHeight));\n\n            if (_canResize)\n            {\n                _topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));\n                _topRight.Arrange(new Rect(desireWidth - adornerWidth / 2, -adornerHeight / 2, adornerWidth,\n                    adornerHeight));\n                _bottomLeft.Arrange(new Rect(-adornerWidth / 2, desireHeight - adornerHeight / 2, adornerWidth,\n                    adornerHeight));\n                _bottomRight.Arrange(new Rect(desireWidth - adornerWidth / 2, desireHeight - adornerHeight / 2,\n                    adornerWidth, adornerHeight));\n\n                _top.Arrange(new Rect(desireWidth / 2 - adornerWidth / 2, -adornerHeight / 2, adornerWidth,\n                    adornerHeight));\n                _left.Arrange(new Rect(-adornerWidth / 2, desireHeight / 2 - adornerHeight / 2, adornerWidth,\n                    adornerHeight));\n                _right.Arrange(new Rect(desireWidth - adornerWidth / 2, desireHeight / 2 - adornerHeight / 2,\n                    adornerWidth, adornerHeight));\n                _bottom.Arrange(new Rect(desireWidth / 2 - adornerWidth / 2, desireHeight - adornerHeight / 2,\n                    adornerWidth, adornerHeight));\n            }\n\n            return FinalSize;\n        }\n\n        protected override int VisualChildrenCount => _visualChildren.Count;\n\n        protected override Visual GetVisualChild(int Index) => _visualChildren[Index];\n    }\n}"
  },
  {
    "path": "src/Captura/Presentation/PuncturedRect.cs",
    "content": "﻿using System;\nusing System.Windows.Shapes;\nusing System.Windows;\nusing System.Windows.Media;\n\nnamespace Captura\n{\n    public class PuncturedRect : Shape\n    {\n        public static readonly DependencyProperty RectInteriorProperty =\n            DependencyProperty.Register(\n                nameof(RectInterior),\n                typeof(Rect),\n                typeof(PuncturedRect),\n                new FrameworkPropertyMetadata(\n                    new Rect(0, 0, 0, 0),\n                    FrameworkPropertyMetadataOptions.AffectsRender,\n                    null,\n                    CoerceRectInterior\n                ),\n                null\n            );\n\n        static object CoerceRectInterior(DependencyObject D, object Value)\n        {\n            if (D is PuncturedRect pr && Value is Rect rcProposed)\n            {\n                var rcExterior = pr.RectExterior;\n\n                var left = Math.Max(rcProposed.Left, rcExterior.Left);\n                var top = Math.Max(rcProposed.Top, rcExterior.Top);\n                var width = Math.Min(rcProposed.Right, rcExterior.Right) - left;\n                var height = Math.Min(rcProposed.Bottom, rcExterior.Bottom) - top;\n\n                return new Rect(left, top, width, height);\n            }\n\n            return Value;\n        }\n\n        public Rect RectInterior\n        {\n            get => (Rect)GetValue(RectInteriorProperty);\n            set => SetValue(RectInteriorProperty, value);\n        }\n        \n        public static readonly DependencyProperty RectExteriorProperty =\n            DependencyProperty.Register(\n                nameof(RectExterior),\n                typeof(Rect),\n                typeof(PuncturedRect),\n                new FrameworkPropertyMetadata(\n                    new Rect(0, 0, double.MaxValue, double.MaxValue),\n                    FrameworkPropertyMetadataOptions.AffectsMeasure |\n                    FrameworkPropertyMetadataOptions.AffectsArrange |\n                    FrameworkPropertyMetadataOptions.AffectsParentMeasure |\n                    FrameworkPropertyMetadataOptions.AffectsParentArrange |\n                    FrameworkPropertyMetadataOptions.AffectsRender\n                ),\n                null\n            );\n\n        public Rect RectExterior\n        {\n            get => (Rect)GetValue(RectExteriorProperty);\n            set => SetValue(RectExteriorProperty, value);\n        }\n        \n        public PuncturedRect() : this(new Rect(0, 0, double.MaxValue, double.MaxValue), new Rect()) { }\n\n        public PuncturedRect(Rect RectExterior, Rect RectInterior)\n        {\n            this.RectInterior = RectInterior;\n            this.RectExterior = RectExterior;\n        }\n        \n        protected override Geometry DefiningGeometry\n        {\n            get\n            {\n                var pthgExt = new PathGeometry();\n                var pthfExt = new PathFigure {StartPoint = RectExterior.TopLeft};\n                pthfExt.Segments.Add(new LineSegment(RectExterior.TopRight, false));\n                pthfExt.Segments.Add(new LineSegment(RectExterior.BottomRight, false));\n                pthfExt.Segments.Add(new LineSegment(RectExterior.BottomLeft, false));\n                pthfExt.Segments.Add(new LineSegment(RectExterior.TopLeft, false));\n                pthgExt.Figures.Add(pthfExt);\n\n                var rectIntSect = Rect.Intersect(RectExterior, RectInterior);\n                var pthgInt = new PathGeometry();\n                var pthfInt = new PathFigure {StartPoint = rectIntSect.TopLeft};\n                pthfInt.Segments.Add(new LineSegment(rectIntSect.TopRight, false));\n                pthfInt.Segments.Add(new LineSegment(rectIntSect.BottomRight, false));\n                pthfInt.Segments.Add(new LineSegment(rectIntSect.BottomLeft, false));\n                pthfInt.Segments.Add(new LineSegment(rectIntSect.TopLeft, false));\n                pthgInt.Figures.Add(pthfInt);\n\n                return new CombinedGeometry(GeometryCombineMode.Exclude, pthgExt, pthgInt);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Presentation/Themes/Expander.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\n    <Style TargetType=\"ToggleButton\"\n           x:Key=\"ExpenderToggleButton\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{x:Null}\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonText}\" />\n        <Setter Property=\"Cursor\" Value=\"Hand\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"ToggleButton\">\n                    <Grid x:Name=\"grid\"\n                          MinWidth=\"25\"\n                          Margin=\"7,12,0,0\"\n                          VerticalAlignment=\"Top\"\n                          Background=\"{TemplateBinding Background}\"\n                          RenderTransformOrigin=\"0.5,0.5\">\n                        <Grid.Resources>\n                            <PathGeometry x:Key=\"IconExpander\">M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M7,10L12,15L17,10H7Z</PathGeometry>\n                        </Grid.Resources>\n                        <Path x:Name=\"icon\"\n                              Data=\"{StaticResource IconExpander}\" \n                              Width=\"20\"\n                              Height=\"20\"\n                              Fill=\"{TemplateBinding Foreground}\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              Opacity=\"0.6\"/>\n                        <Grid.RenderTransform>\n                            <TransformGroup>\n                                <RotateTransform Angle=\"0\" x:Name=\"RotateTransform\"/>\n                                <ScaleTransform x:Name=\"IconScale\"/>\n                            </TransformGroup>\n                        </Grid.RenderTransform>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsMouseOver\" Value=\"True\">\n                            <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonTextHover}\" />\n                            <Trigger.EnterActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"icon\"\n                                                         Storyboard.TargetProperty=\"Opacity\"\n                                                         To=\"1\"\n                                                         Duration=\"0:0:0.15\" />\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.EnterActions>\n                            <Trigger.ExitActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"icon\"\n                                                         Storyboard.TargetProperty=\"Opacity\"\n                                                         To=\"0.6\"\n                                                         Duration=\"0:0:0.15\" />\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.ExitActions>\n                        </Trigger>\n                        <Trigger Property=\"IsPressed\" Value=\"True\">\n                            <Setter Property=\"Foreground\" Value=\"{DynamicResource Accent}\" />\n                            <Trigger.EnterActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"IconScale\"\n                                                         Storyboard.TargetProperty=\"ScaleX\"\n                                                         To=\"0.9\"\n                                                         Duration=\"0:0:0.15\" />\n                                        <DoubleAnimation Storyboard.TargetName=\"IconScale\"\n                                                         Storyboard.TargetProperty=\"ScaleY\"\n                                                         To=\"0.9\"\n                                                         Duration=\"0:0:0.15\" />\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.EnterActions>\n                            <Trigger.ExitActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"IconScale\"\n                                                         Storyboard.TargetProperty=\"ScaleX\"\n                                                         To=\"1\"\n                                                         Duration=\"0:0:0.15\" />\n                                        <DoubleAnimation Storyboard.TargetName=\"IconScale\"\n                                                         Storyboard.TargetProperty=\"ScaleY\"\n                                                         To=\"1\"\n                                                         Duration=\"0:0:0.15\" />\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.ExitActions>\n                        </Trigger>\n                        <Trigger Property=\"IsChecked\" Value=\"True\">\n                            <Trigger.EnterActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"RotateTransform\"\n                                                         Storyboard.TargetProperty=\"Angle\"\n                                                         To=\"180\"\n                                                         Duration=\"00:00:00.2\"/>\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.EnterActions>\n                            <Trigger.ExitActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"RotateTransform\"\n                                                         Storyboard.TargetProperty=\"Angle\"\n                                                         To=\"0\"\n                                                         Duration=\"00:00:00.2\"/>\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.ExitActions>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"Expander\">\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"Expander\">\n                    <Grid>\n                        <Grid.RowDefinitions>\n                            <RowDefinition Height=\"Auto\"/>\n                            <RowDefinition Name=\"ContentRow\"\n                                           Height=\"*\"\n                                           MaxHeight=\"0\"/>\n                        </Grid.RowDefinitions>\n                        \n                        <Grid>\n                            <Grid.ColumnDefinitions>\n                                <ColumnDefinition Width=\"Auto\" />\n                                <ColumnDefinition Width=\"*\" />\n                            </Grid.ColumnDefinitions>\n\n                            <ToggleButton IsChecked=\"{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}\"\n                                          Style=\"{StaticResource ExpenderToggleButton}\"/>\n                            \n                            <ContentPresenter Grid.Column=\"1\"\n                                              Margin=\"4\" \n                                              ContentSource=\"Header\" \n                                              RecognizesAccessKey=\"True\" />\n                        </Grid>\n                        \n                        <ContentPresenter Margin=\"4\"\n                                          Name=\"Content\" \n                                          Grid.Row=\"1\"/>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsExpanded\" Value=\"True\">\n                            <Trigger.EnterActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"ContentRow\"\n                                                         Storyboard.TargetProperty=\"MaxHeight\"\n                                                         To=\"1000\"\n                                                         Duration=\"00:00:00.25\"/>\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.EnterActions>\n                            <Trigger.ExitActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"ContentRow\"\n                                                         Storyboard.TargetProperty=\"MaxHeight\"\n                                                         To=\"0\"\n                                                         Duration=\"00:00:00.25\"/>\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.ExitActions>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary>"
  },
  {
    "path": "src/Captura/Presentation/Themes/Generic.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\">\n    <Style TargetType=\"Label\" BasedOn=\"{StaticResource {x:Type Label}}\">\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\" />\n    </Style>\n\n    <Style x:Key=\"TextColor\" TargetType=\"TextBlock\">\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource WindowText}\"/>\n    </Style>\n\n    <Style TargetType=\"xctk:IntegerUpDown\" BasedOn=\"{StaticResource {x:Type xctk:IntegerUpDown}}\">\n        <Setter Property=\"Minimum\" Value=\"0\"/>\n        <Setter Property=\"Padding\" Value=\"0,0,5,0\"/>\n    </Style>\n\n    <Style TargetType=\"Path\">\n        <Setter Property=\"Fill\" Value=\"{DynamicResource ModernButtonText}\"/>\n        <Style.Triggers>\n            <Trigger Property=\"IsEnabled\" Value=\"False\">\n                <Setter Property=\"Fill\" Value=\"{DynamicResource ButtonTextDisabled}\"/>\n            </Trigger>\n        </Style.Triggers>\n    </Style>\n    \n    <Style TargetType=\"xctk:ColorPicker\" BasedOn=\"{StaticResource {x:Type xctk:ColorPicker}}\">\n        <Setter Property=\"ColorMode\" Value=\"ColorCanvas\"/>\n        <Setter Property=\"ShowAdvancedButton\" Value=\"False\"/>\n    </Style>\n    \n    <Style TargetType=\"xctk:SplitButton\" BasedOn=\"{StaticResource {x:Type xctk:SplitButton}}\">\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonText}\"/>\n    </Style>\n\n    <Style TargetType=\"xctk:DropDownButton\" BasedOn=\"{StaticResource {x:Type xctk:DropDownButton}}\">\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonText}\"/>\n    </Style>\n\n    <Style TargetType=\"TabItem\">\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource ItemText}\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"TabItem\">\n                    <Grid Name=\"Panel\"\n                          Background=\"Transparent\">\n                        <ContentPresenter Content=\"{TemplateBinding Header}\"\n                                          Margin=\"10,2\"/>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsSelected\" \n                                 Value=\"True\">\n                            <Setter TargetName=\"Panel\"\n                                    Property=\"Background\"\n                                    Value=\"{DynamicResource Accent}\" />\n                            <Setter Property=\"Foreground\" Value=\"White\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary>"
  },
  {
    "path": "src/Captura/Presentation/Themes/LICENSE.md",
    "content": "ModernUI\n(c) FirstFloor Software\n\nMicrosoft Public License (Ms-PL)\n\nThis license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.\n\n1. Definitions\n\nThe terms \"reproduce,\" \"reproduction,\" \"derivative works,\" and \"distribution\" have the same meaning here as under U.S. copyright law.\n\nA \"contribution\" is the original software, or any additions or changes to the software.\n\nA \"contributor\" is any person that distributes its contribution under this license.\n\n\"Licensed patents\" are a contributor's patent claims that read directly on its contribution.\n\n2. Grant of Rights\n\n(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.\n\n(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.\n\n3. Conditions and Limitations\n\n(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.\n\n(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.\n\n(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.\n\n(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.\n\n(E) The software is licensed \"as-is.\" You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement."
  },
  {
    "path": "src/Captura/Presentation/Themes/ModernButton.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:controls=\"clr-namespace:Captura\">\n\n    <Style TargetType=\"controls:ModernButton\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{x:Null}\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonText}\" />\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"Cursor\" Value=\"Hand\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"controls:ModernButton\">\n                    <Grid x:Name=\"grid\"\n                          Background=\"{TemplateBinding Background}\"\n                          MinHeight=\"36\"\n                          MinWidth=\"36\">\n                        <Path x:Name=\"icon\"\n                              Data=\"{TemplateBinding IconData}\" \n                              Width=\"15\"\n                              Height=\"15\"\n                              Fill=\"{TemplateBinding Foreground}\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              VerticalAlignment=\"Center\"\n                              Opacity=\"0.8\">\n                            <Path.LayoutTransform>\n                                <ScaleTransform x:Name=\"IconScale\"/>\n                            </Path.LayoutTransform>\n                        </Path>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsMouseOver\" Value=\"True\">\n                            <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonTextHover}\" />\n                            <Setter Property=\"Opacity\" TargetName=\"icon\" Value=\"1\"/>\n                            <Trigger.EnterActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"IconScale\"\n                                                         Storyboard.TargetProperty=\"ScaleX\"\n                                                         To=\"1.2\"\n                                                         Duration=\"0:0:0.15\" />\n                                        <DoubleAnimation Storyboard.TargetName=\"IconScale\"\n                                                         Storyboard.TargetProperty=\"ScaleY\"\n                                                         To=\"1.2\"\n                                                         Duration=\"0:0:0.15\" />\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.EnterActions>\n                            <Trigger.ExitActions>\n                                <BeginStoryboard>\n                                    <Storyboard>\n                                        <DoubleAnimation Storyboard.TargetName=\"IconScale\"\n                                                         Storyboard.TargetProperty=\"ScaleX\"\n                                                         To=\"1\"\n                                                         Duration=\"0:0:0.15\" />\n                                        <DoubleAnimation Storyboard.TargetName=\"IconScale\"\n                                                         Storyboard.TargetProperty=\"ScaleY\"\n                                                         To=\"1\"\n                                                         Duration=\"0:0:0.15\" />\n                                    </Storyboard>\n                                </BeginStoryboard>\n                            </Trigger.ExitActions>\n                        </Trigger>\n                        <Trigger Property=\"IsPressed\" Value=\"True\">\n                            <Setter Property=\"Foreground\" Value=\"{DynamicResource Accent}\" />\n                        </Trigger>\n                        <Trigger Property=\"IsEnabled\" Value=\"False\">\n                            <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonTextDisabled}\" />\n                            <Setter TargetName=\"icon\" Property=\"Opacity\" Value=\"0.3\" />\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"controls:ModernButton\" x:Key=\"IconButton\">\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"controls:ModernButton\">\n                    <Button HorizontalContentAlignment=\"Left\"\n                            Margin=\"10\"\n                            Padding=\"0\"\n                            MinWidth=\"150\"\n                            Command=\"{TemplateBinding Command}\"\n                            CommandParameter=\"{TemplateBinding CommandParameter}\">\n                        <StackPanel Orientation=\"Horizontal\">\n                            <Path Data=\"{TemplateBinding IconData}\"\n                                  Margin=\"10\"\n                                  Width=\"20\"\n                                  Height=\"20\"\n                                  Stretch=\"Uniform\"\n                                  HorizontalAlignment=\"Center\"/>\n                            <GridSplitter Width=\"3\"\n                                          IsEnabled=\"False\"\n                                          Margin=\"5,0\"/>\n                            <TextBlock Text=\"{TemplateBinding Content}\"\n                                       VerticalAlignment=\"Center\"\n                                       Margin=\"5,0\"\n                                       FontSize=\"13\"/>\n                        </StackPanel>\n                    </Button>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary>"
  },
  {
    "path": "src/Captura/Presentation/Themes/ModernToggleButton.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:controls=\"clr-namespace:Captura\">\n\n    <Style TargetType=\"controls:ModernToggleButton\">\n        <Setter Property=\"FocusVisualStyle\" Value=\"{x:Null}\"/>\n        <Setter Property=\"HorizontalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"VerticalContentAlignment\" Value=\"Center\" />\n        <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonText}\" />\n        <Setter Property=\"Background\" Value=\"Transparent\"/>\n        <Setter Property=\"Cursor\" Value=\"Hand\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"controls:ModernToggleButton\">\n                    <Grid x:Name=\"grid\"\n                          Background=\"{TemplateBinding Background}\"\n                          MinHeight=\"36\"\n                          MinWidth=\"36\">\n                        <Ellipse Width=\"30\"\n                                 Height=\"30\"\n                                 Name=\"bg\"/>\n                        <Path x:Name=\"icon\"\n                              Data=\"{TemplateBinding IconData}\" \n                              Width=\"14\"\n                              Height=\"14\"\n                              Fill=\"{TemplateBinding Foreground}\"\n                              Stretch=\"Uniform\"\n                              HorizontalAlignment=\"Center\"\n                              VerticalAlignment=\"Center\"\n                              Opacity=\"0.7\"/>\n                    </Grid>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsMouseOver\" Value=\"True\">\n                            <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonTextHover}\" />\n                            <Setter Property=\"Opacity\" TargetName=\"icon\" Value=\"1\"/>\n                        </Trigger>\n                        <Trigger Property=\"IsPressed\" Value=\"True\">\n                            <Setter TargetName=\"icon\" Property=\"Fill\" Value=\"{DynamicResource Accent}\" />\n                        </Trigger>\n                        <Trigger Property=\"IsEnabled\" Value=\"False\">\n                            <Setter Property=\"Foreground\" Value=\"{DynamicResource ModernButtonTextDisabled}\" />\n                            <Setter TargetName=\"icon\" Property=\"Opacity\" Value=\"0.3\" />\n                        </Trigger>\n                        <Trigger Property=\"IsChecked\" Value=\"True\">\n                            <Setter Property=\"Fill\" Value=\"{DynamicResource Accent}\" TargetName=\"icon\"/>\n                            <Setter Property=\"Stroke\" Value=\"{DynamicResource Accent}\" TargetName=\"bg\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary>"
  },
  {
    "path": "src/Captura/Presentation/Themes/ModernTogglePill.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\n    <Style x:Key=\"ModernTogglePill\" TargetType=\"CheckBox\">\n        <Setter Property=\"Padding\" Value=\"16,3,16,5\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"CheckBox\">\n                    <Border VerticalAlignment=\"Center\"\n                            CornerRadius=\"12\"\n                            BorderThickness=\"1\"\n                            Margin=\"{TemplateBinding Margin}\"\n                            Name=\"border\"\n                            BorderBrush=\"{DynamicResource ItemBorder}\">\n                        <Label ToolTip=\"{TemplateBinding ToolTip}\"\n                               Content=\"{TemplateBinding Content}\"\n                               BorderThickness=\"0\"\n                               Cursor=\"Hand\"\n                               Name=\"label\"\n                               Padding=\"{TemplateBinding Padding}\"/>\n                    </Border>\n                    <ControlTemplate.Triggers>\n                        <Trigger Property=\"IsChecked\" Value=\"True\">\n                            <Setter Property=\"Foreground\"\n                                    TargetName=\"label\"\n                                    Value=\"{DynamicResource Accent}\"/>\n                            <Setter Property=\"BorderBrush\"\n                                    TargetName=\"border\"\n                                    Value=\"{DynamicResource Accent}\"/>\n                        </Trigger>\n                    </ControlTemplate.Triggers>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary>"
  },
  {
    "path": "src/Captura/Presentation/Themes/RegionPickerMagnifier.xaml",
    "content": "﻿<!--***********************************************************************************\n   Extended WPF Toolkit\n   Copyright (C) 2007-2013 Xceed Software Inc.\n   This program is provided to you under the terms of the Microsoft Public\n   License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license \n   For more features, controls, and fast professional support,\n   pick up the Plus Edition at http://xceed.com/wpf_toolkit\n   Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids\n  **********************************************************************************-->\n\n<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n                    xmlns:converters=\"clr-namespace:Xceed.Wpf.Toolkit.Mag.Converters;assembly=Xceed.Wpf.Toolkit\">\n    <converters:RadiusConverter x:Key=\"RadiusConverter\" />\n    <xctk:BorderThicknessToStrokeThicknessConverter x:Key=\"BorderToStrokeThicknessConverter\" />\n    \n    <Style TargetType=\"{x:Type xctk:Magnifier}\" x:Key=\"RegionPickerMagnifier\">\n        <Setter Property=\"IsHitTestVisible\" Value=\"False\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type xctk:Magnifier}\">\n                    <Grid>\n                        <Ellipse Fill=\"{TemplateBinding Background}\" />\n                        <Ellipse Stroke=\"{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}\" \n                                 StrokeThickness=\"{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BorderToStrokeThicknessConverter}}\">\n                            <Ellipse.Fill>\n                                <VisualBrush x:Name=\"PART_VisualBrush\"\n                                             ViewboxUnits=\"Absolute\"\n                                             Visual=\"{Binding Target, RelativeSource={RelativeSource TemplatedParent}}\" />\n                            </Ellipse.Fill>\n                        </Ellipse>\n\n                        <Grid Margin=\"5\">\n                            <Grid.Resources>\n                                <Style TargetType=\"Rectangle\">\n                                    <Setter Property=\"Fill\" Value=\"White\"/>\n                                    <Setter Property=\"Stroke\" Value=\"#B7000000\"/>\n                                    <Setter Property=\"StrokeThickness\" Value=\"1\"/>\n                                </Style>\n                            </Grid.Resources>\n                            <Grid.ColumnDefinitions>\n                                <ColumnDefinition/>\n                                <ColumnDefinition Width=\"20\"/>\n                                <ColumnDefinition/>\n                            </Grid.ColumnDefinitions>\n                            <Grid.RowDefinitions>\n                                <RowDefinition/>\n                                <RowDefinition Height=\"20\"/>\n                                <RowDefinition/>\n                            </Grid.RowDefinitions>\n\n                            <Rectangle Grid.Row=\"1\"\n                                       Height=\"5\"/>\n                            <Rectangle Grid.Row=\"1\"\n                                       Grid.Column=\"2\"\n                                       Height=\"5\"/>\n                            \n                            <Rectangle Grid.Column=\"1\"\n                                       Grid.Row=\"0\"\n                                       Width=\"5\"/>\n                            <Rectangle Grid.Column=\"1\"\n                                       Grid.Row=\"2\"\n                                       Width=\"5\"/>\n                        </Grid>\n                    </Grid>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary>"
  },
  {
    "path": "src/Captura/Presentation/Themes/RoundSlider.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\n    <SolidColorBrush x:Key=\"HorizontalSliderTrackNormalBackground\"\n                     Color=\"#FFE7EAEA\"/>\n    <LinearGradientBrush x:Key=\"HorizontalSliderTrackNormalBorder\" \n                         EndPoint=\"0,1\" \n                         StartPoint=\"0,0\">\n        <GradientStop Color=\"#FFAEB1AF\"\n                      Offset=\"0.1\"/>\n        <GradientStop Color=\"White\"\n                      Offset=\".9\"/>\n    </LinearGradientBrush>\n    <BooleanToVisibilityConverter x:Key=\"BooleanToVisibilityConverter\"/>\n    <Style x:Key=\"SliderRepeatButtonStyle\"\n           TargetType=\"{x:Type RepeatButton}\">\n        <Setter Property=\"OverridesDefaultStyle\"\n                Value=\"true\"/>\n        <Setter Property=\"IsTabStop\"\n                Value=\"false\"/>\n        <Setter Property=\"Focusable\"\n                Value=\"false\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type RepeatButton}\">\n                    <Rectangle Fill=\"Transparent\"/>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style x:Key=\"CustomThumbForSlider\"\n           TargetType=\"{x:Type Thumb}\">\n        <Setter Property=\"OverridesDefaultStyle\"\n                Value=\"True\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Thumb}\">\n                    <Ellipse Fill=\"White\"\n                             Stroke=\"#B7000000\"\n                             Height=\"15\"\n                             Width=\"15\"/>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n\n    <Style TargetType=\"{x:Type Slider}\"\n           x:Key=\"RoundSlider\">\n        <Setter Property=\"VerticalAlignment\" \n                Value=\"Center\"/>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate TargetType=\"{x:Type Slider}\">\n                    <Border Background=\"{TemplateBinding Background}\"\n                            BorderBrush=\"{TemplateBinding BorderBrush}\" \n                            BorderThickness=\"{TemplateBinding BorderThickness}\">\n                        <Grid>\n                            <Grid.RowDefinitions>\n                                <RowDefinition Height=\"Auto\"/>\n                                <RowDefinition Height=\"Auto\"\n                                               MinHeight=\"{TemplateBinding MinHeight}\"/>\n                                <RowDefinition Height=\"Auto\"/>\n                            </Grid.RowDefinitions>\n                            <TickBar x:Name=\"TopTick\" \n                                     Visibility=\"Collapsed\" \n                                     Fill=\"{TemplateBinding Foreground}\"\n                                     Placement=\"Top\" \n                                     Height=\"4\"\n                                     Grid.Row=\"0\"/>\n                            <TickBar x:Name=\"BottomTick\" \n                                     Visibility=\"Collapsed\"\n                                     Fill=\"{TemplateBinding Foreground}\"\n                                     Placement=\"Bottom\" \n                                     Height=\"4\" \n                                     Grid.Row=\"0\"/>\n                            <Border x:Name=\"TrackBackground\" \n                                    Background=\"{StaticResource HorizontalSliderTrackNormalBackground}\"\n                                    BorderBrush=\"{StaticResource HorizontalSliderTrackNormalBorder}\"                                        \n                                    BorderThickness=\"1\" \n                                    CornerRadius=\"1\"\n                                    Margin=\"5,0\" \n                                    VerticalAlignment=\"Center\"\n                                    Height=\"4.0\"\n                                    Grid.Row=\"1\">\n                                <Canvas Margin=\"-6,-1\">\n                                    <Rectangle Visibility=\"{TemplateBinding IsSelectionRangeEnabled, Converter={StaticResource BooleanToVisibilityConverter}}\" \n                                               x:Name=\"PART_SelectionRange\" \n                                               Height=\"4.0\"\n                                               Fill=\"{DynamicResource Accent}\"\n                                               StrokeThickness=\"1.0\"/>\n                                </Canvas>\n                            </Border>\n                            <Track x:Name=\"PART_Track\" \n                                   Grid.Row=\"1\">\n                                <Track.DecreaseRepeatButton>\n                                    <RepeatButton Style=\"{StaticResource SliderRepeatButtonStyle}\" \n                                                  Command=\"{x:Static Slider.DecreaseLarge}\"/>\n                                </Track.DecreaseRepeatButton>\n                                <Track.IncreaseRepeatButton>\n                                    <RepeatButton Style=\"{StaticResource SliderRepeatButtonStyle}\" \n                                                  Command=\"{x:Static Slider.IncreaseLarge}\"/>\n                                </Track.IncreaseRepeatButton>\n                                <Track.Thumb>\n                                    <Thumb x:Name=\"Thumb\" \n                                           Style=\"{StaticResource CustomThumbForSlider}\"\n                                           Background=\"Black\"/>\n                                </Track.Thumb>\n                            </Track>\n                        </Grid>\n                    </Border>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary>"
  },
  {
    "path": "src/Captura/Presentation/Themes/VirtualizingItemsControl.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\n    <Style x:Key=\"VirtualizingItemsControl\"\n           TargetType=\"ItemsControl\">\n        <Setter Property=\"VirtualizingPanel.IsVirtualizing\" Value=\"True\"/>\n        <Setter Property=\"VirtualizingPanel.ScrollUnit\" Value=\"Pixel\"/>\n        <Setter Property=\"ScrollViewer.CanContentScroll\" Value=\"True\"/>\n        <Setter Property=\"ItemsPanel\">\n            <Setter.Value>\n                <ItemsPanelTemplate>\n                    <VirtualizingStackPanel/>\n                </ItemsPanelTemplate>\n            </Setter.Value>\n        </Setter>\n        <Setter Property=\"Template\">\n            <Setter.Value>\n                <ControlTemplate>\n                    <ScrollViewer>\n                        <ItemsPresenter/>\n                    </ScrollViewer>\n                </ControlTemplate>\n            </Setter.Value>\n        </Setter>\n    </Style>\n</ResourceDictionary>"
  },
  {
    "path": "src/Captura/Presentation/WpfExtensions.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.IO;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\nusing System.Windows.Media.Animation;\nusing System.Windows.Media.Imaging;\nusing Captura.Video;\nusing Captura.ViewModels;\nusing Microsoft.Win32;\nusing Reactive.Bindings;\nusing Color = System.Windows.Media.Color;\nusing ColorConverter = System.Windows.Media.ColorConverter;\nusing DColor = System.Drawing.Color;\n\nnamespace Captura\n{\n    public static class WpfExtensions\n    {\n        public static void ShowAndFocus(this Window W)\n        {\n            if (W.IsVisible && W.WindowState == WindowState.Minimized)\n            {\n                W.WindowState = WindowState.Normal;\n            }\n\n            W.Show();\n\n            W.Activate();\n        }\n\n        public static Rectangle ApplyDpi(this RectangleF Rectangle)\n        {\n            return new Rectangle((int)(Rectangle.Left * Dpi.X),\n                (int)(Rectangle.Top * Dpi.Y),\n                (int)(Rectangle.Width * Dpi.X),\n                (int)(Rectangle.Height * Dpi.Y));\n        }\n\n        public static DColor ToDrawingColor(this Color C)\n        {\n            return DColor.FromArgb(C.A, C.R, C.G, C.B);\n        }\n\n        public static Color ToWpfColor(this DColor C)\n        {\n            return Color.FromArgb(C.A, C.R, C.G, C.B);\n        }\n\n        public static Color ParseColor(string S)\n        {\n            if (ColorConverter.ConvertFromString(S) is Color c)\n                return c;\n\n            return Colors.Transparent;\n        }\n\n        public static void Shake(this FrameworkElement Element)\n        {\n            Element.Dispatcher.Invoke(() =>\n            {\n                var transform = new TranslateTransform();\n                Element.RenderTransform = transform;\n\n                const int delta = 5;\n\n                var animation = new DoubleAnimationUsingKeyFrames\n                {\n                    AutoReverse = true,\n                    RepeatBehavior = new RepeatBehavior(1),\n                    Duration = new Duration(TimeSpan.FromMilliseconds(200)),\n                    KeyFrames =\n                    {\n                        new EasingDoubleKeyFrame(0, KeyTime.FromPercent(0)),\n                        new EasingDoubleKeyFrame(delta, KeyTime.FromPercent(0.25)),\n                        new EasingDoubleKeyFrame(0, KeyTime.FromPercent(0.5)),\n                        new EasingDoubleKeyFrame(-delta, KeyTime.FromPercent(0.75)),\n                        new EasingDoubleKeyFrame(0, KeyTime.FromPercent(1))\n                    }\n                };\n\n                transform.BeginAnimation(TranslateTransform.XProperty, animation);\n            });\n        }\n\n        public static bool SaveToPickedFile(this BitmapSource Bitmap, string DefaultFileName = null)\n        {\n            var sfd = new SaveFileDialog\n            {\n                AddExtension = true,\n                DefaultExt = \".png\",\n                Filter = \"PNG Image|*.png|JPEG Image|*.jpg;*.jpeg|Bitmap Image|*.bmp|TIFF Image|*.tiff\"\n            };\n\n            if (DefaultFileName != null)\n            {\n                sfd.FileName = Path.GetFileNameWithoutExtension(DefaultFileName);\n\n                var dir = Path.GetDirectoryName(DefaultFileName);\n\n                if (dir != null)\n                {\n                    sfd.InitialDirectory = dir;\n                }\n            }\n            else sfd.FileName = \"Untitled\";\n\n            if (!sfd.ShowDialog().GetValueOrDefault())\n                return false;\n\n            BitmapEncoder encoder;\n\n            // Filter Index starts from 1\n            switch (sfd.FilterIndex)\n            {\n                case 2:\n                    encoder = new JpegBitmapEncoder();\n                    break;\n\n                case 3:\n                    encoder = new BmpBitmapEncoder();\n                    break;\n\n                case 4:\n                    encoder = new TiffBitmapEncoder();\n                    break;\n\n                default:\n                    encoder = new PngBitmapEncoder();\n                    break;\n            }\n\n            encoder.Frames.Add(BitmapFrame.Create(Bitmap));\n\n            using (var stream = sfd.OpenFile())\n            {\n                encoder.Save(stream);\n            }\n\n            return true;\n        }\n\n        public static void Bind(this FrameworkElement Control, DependencyProperty DependencyProperty, IReactiveProperty Property)\n        {\n            Control.SetBinding(DependencyProperty,\n                new Binding(nameof(Property.Value))\n                {\n                    Source = Property,\n                    Mode = BindingMode.TwoWay\n                });\n        }\n\n        public static void BindOne<T>(this FrameworkElement Control, DependencyProperty DependencyProperty, IReadOnlyReactiveProperty<T> Property)\n        {\n            Control.SetBinding(DependencyProperty,\n                new Binding(nameof(Property.Value))\n                {\n                    Source = Property,\n                    Mode = BindingMode.OneWay\n                });\n        }\n\n        public static async Task<ImageSource> GetBackground()\n        {\n            var vm = ServiceProvider.Get<VideoSourcesViewModel>();\n\n            IBitmapImage bmp;\n\n            switch (vm.SelectedVideoSourceKind?.Source)\n            {\n                case NoVideoItem _:\n                    bmp = ScreenShot.Capture();\n                    break;\n\n                default:\n                    var screenShotModel = ServiceProvider.Get<ScreenShotModel>();\n                    bmp = await screenShotModel.GetScreenShot(vm.SelectedVideoSourceKind, true);\n                    break;\n            }\n\n            if (bmp == null)\n            {\n                bmp = ScreenShot.Capture();\n            }\n\n            using (bmp)\n            {\n                var stream = new MemoryStream();\n                bmp.Save(stream, ImageFormats.Png);\n\n                stream.Seek(0, SeekOrigin.Begin);\n\n                var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default);\n                return decoder.Frames[0];\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\n\n[assembly: AssemblyTitle(nameof(Captura))]\n[assembly: AssemblyDescription(\"Captures Screen/Window as ScreenShot/ScreenCast along with Audio from Microphone/Loopback, Mouse Cursor, Clicks and Keystrokes\")]\n[assembly: AssemblyCompany(\"Mathew Sachin\")]\n[assembly: AssemblyProduct(nameof(Captura))]\n[assembly: AssemblyCopyright(\"(c) 2018 Mathew Sachin\")]\n[assembly: AssemblyTrademark(nameof(Captura))]\n[assembly: AssemblyVersion(\"0.0.0\")]\n"
  },
  {
    "path": "src/Captura/ValueConverters/DrawingToWpfColorConverter.cs",
    "content": "using System;\nusing System.Drawing;\nusing System.Globalization;\nusing System.Windows.Data;\nusing WpfColor = System.Windows.Media.Color;\n\nnamespace Captura\n{\n    public class DrawingToWpfColorConverter : IValueConverter\n    {\n        public object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (Value is Color c)\n                return c.ToWpfColor();\n\n            return Binding.DoNothing;\n        }\n\n        public object ConvertBack(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            switch (Value)\n            {\n                case string s:\n                    return ColorTranslator.FromHtml(s);\n\n                case WpfColor c:\n                    return c.ToString();\n\n                default:\n                    return Binding.DoNothing;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/GetTypeConverter.cs",
    "content": "using System;\nusing System.Globalization;\n\nnamespace Captura\n{\n    public class GetTypeConverter : OneWayConverter\n    {\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            return Value?.GetType();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/InkToolToIconConverter.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Windows.Controls;\nusing System.Windows.Media;\n\nnamespace Captura\n{\n    public class InkToolToIconConverter : OneWayConverter\n    {\n        static string GetPath(object Value)\n        {\n            var icons = ServiceProvider.Get<IIconSet>();\n\n            switch (Value)\n            {\n                case InkCanvasEditingMode.Ink:\n                    return icons.Pencil;\n\n                case InkCanvasEditingMode.EraseByPoint:\n                    return icons.Eraser;\n\n                case InkCanvasEditingMode.EraseByStroke:\n                    return icons.StrokeEraser;\n\n                case InkCanvasEditingMode.Select:\n                    return icons.Select;\n            }\n\n            return icons.Cursor;\n        }\n\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            return Geometry.Parse(GetPath(Value));\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/IntegralTimeSpanConverter.cs",
    "content": "﻿using System;\nusing System.Windows.Data;\nusing System.Globalization;\n\nnamespace Captura\n{\n    public class IntegralTimeSpanConverter : OneWayConverter\n    {\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (Value is TimeSpan t)\n                return TimeSpan.FromSeconds((int) t.TotalSeconds);\n\n            return Binding.DoNothing;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/ValueConverters/IsLessThanConverter.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\n\nnamespace Captura\n{\n    public class IsLessThanConverter : OneWayConverter\n    {\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (double.TryParse(Value?.ToString(), out var left) && double.TryParse(Parameter?.ToString(), out var right))\n            {\n                var b =  left < right;\n\n                if (TargetType == typeof(Visibility))\n                    return b ? Visibility.Visible : Visibility.Collapsed;\n\n                return b;\n            }\n\n            return Binding.DoNothing;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/IsPlayingToButtonStyleConverter.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Captura\n{\n    public class IsPlayingToButtonStyleConverter : OneWayConverter\n    {\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (Value is bool b)\n            {\n                var icons = ServiceProvider.Get<IIconSet>();\n\n                var icon = Geometry.Parse(b ? icons.Stop : icons.Play);\n                var color = b ? Colors.OrangeRed : Colors.LimeGreen;\n\n                return new Style(typeof(ModernButton), (Style) Application.Current.Resources[typeof(ModernButton)])\n                {\n                    Setters =\n                    {\n                        new Setter(ModernButton.IconDataProperty, icon),\n                        new Setter(Control.ForegroundProperty, new SolidColorBrush(color))\n                    }\n                };\n            }\n\n            return Binding.DoNothing;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/LanguageConverter.cs",
    "content": "﻿using System;\nusing System.Windows.Data;\nusing System.Globalization;\n\nnamespace Captura\n{\n    public class LanguageConverter : IValueConverter\n    {\n        public object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (Value is CultureInfo c)\n            {\n                switch (c.Name)\n                {\n                    case \"en\":\n                        return \"English\";\n\n                    case \"zh-CN\":\n                        return \"Chinese (Simplified) (中文简体)\";\n\n                    case \"zh-TW\":\n                        return \"Chinese (Traditional) (中文繁体)\";\n\n                    default:\n                        return $\"{c.DisplayName} ({c.NativeName})\";\n                }\n            }\n\n            return Binding.DoNothing;\n        }\n\n        public object ConvertBack(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            return Binding.DoNothing;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/ValueConverters/NegatingConverter.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\n\nnamespace Captura\n{\n    public class NegatingConverter : IValueConverter\n    {\n        static object DoConvert(object Value)\n        {\n            if (Value is bool b)\n                return !b;\n\n            return Binding.DoNothing;\n        }\n\n        public object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            switch (Value)\n            {\n                case bool b when TargetType == typeof(Visibility):\n                    return b ? Visibility.Collapsed : Visibility.Visible;\n\n                case bool b:\n                    return !b;\n\n                case Visibility visibility when TargetType == typeof(Visibility):\n                    return visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;\n\n                case Visibility visibility:\n                    return visibility == Visibility.Collapsed;\n\n                default:\n                    return Binding.DoNothing;\n            }\n        }\n\n        public object ConvertBack(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            return DoConvert(Value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/NotNullConverter.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Globalization;\nusing System.Windows;\n\nnamespace Captura\n{\n    public class NotNullConverter : OneWayConverter\n    {\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            var b = Value != null;\n\n            switch (Value)\n            {\n                case ICollection collection:\n                    b = collection.Count != 0;\n                    break;\n\n                case string str:\n                    b = !string.IsNullOrWhiteSpace(str);\n                    break;\n\n                case int i:\n                    b = i != 0;\n                    break;\n\n                case double d:\n                    b = Math.Abs(d) > 0.01;\n                    break;\n            }\n\n            if ((Parameter is bool inverse || Parameter is string s && bool.TryParse(s, out inverse)) && inverse)\n                b = !b;\n\n            if (TargetType == typeof(Visibility))\n                return b ? Visibility.Visible : Visibility.Collapsed;\n\n            return b;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/NotRecordingConverter.cs",
    "content": "using Captura.Models;\nusing System;\nusing System.Globalization;\nusing System.Windows.Data;\n\nnamespace Captura\n{\n    public class NotRecordingConverter : OneWayConverter\n    {\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (Value is RecorderState state)\n                return state == RecorderState.NotRecording;\n\n            return Binding.DoNothing;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/OneWayConverter.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.Windows.Data;\n\nnamespace Captura\n{\n    public abstract class OneWayConverter : IValueConverter\n    {\n        public abstract object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture);\n\n        public virtual object ConvertBack(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            return Binding.DoNothing;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/ValueConverters/SecondsToTimeSpanConverter.cs",
    "content": "﻿using System;\nusing System.Windows.Data;\nusing System.Globalization;\n\nnamespace Captura\n{\n    public class SecondsToTimeSpanConverter : IValueConverter\n    {\n        public object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (Value is int seconds)\n                return TimeSpan.FromSeconds(seconds);\n\n            return Binding.DoNothing;\n        }\n\n        public object ConvertBack(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (Value is TimeSpan t)\n                return t.TotalSeconds;\n\n            return Binding.DoNothing;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/ValueConverters/StateToRecordButtonGeometryConverter.cs",
    "content": "using Captura.Models;\nusing System;\nusing System.Globalization;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Captura\n{\n    public class StateToRecordButtonGeometryConverter : OneWayConverter\n    {\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            var icons = ServiceProvider.Get<IIconSet>();\n\n            if (Value is RecorderState state)\n            {\n                return Geometry.Parse(state == RecorderState.NotRecording\n                    ? icons.Record\n                    : icons.Stop);\n            }\n\n            return Binding.DoNothing;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/StateToTaskbarOverlayConverter.cs",
    "content": "using Captura.Models;\nusing System;\nusing System.Globalization;\n\nnamespace Captura\n{\n    public class StateToTaskbarOverlayConverter : OneWayConverter\n    {\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            switch(Value)\n            {\n                case RecorderState.Recording:\n                    return \"/Images/record.ico\";\n\n                case RecorderState.Paused:\n                    return \"/Images/pause.ico\";\n\n                default:\n                    return null;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/StateToTrayIconSourceConverter.cs",
    "content": "using Captura.Models;\nusing System;\nusing System.Globalization;\n\nnamespace Captura\n{\n    public class StateToTrayIconSourceConverter : OneWayConverter\n    {        \n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            switch (Value)\n            {\n                case RecorderState.Recording:\n                    return \"/Images/record.ico\";\n\n                case RecorderState.Paused:\n                    return \"/Images/pause.ico\";\n\n                default:\n                    return \"/Images/Captura.ico\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/StaticResourceConverter.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.Windows;\n\nnamespace Captura\n{\n    public class StaticResourceConverter : OneWayConverter\n    {\n        public override object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            return Value != null ? Application.Current.Resources[Value] : null;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/ValueConverters/TimeSpanToSecondsConverter.cs",
    "content": "﻿using System;\nusing System.Windows.Data;\nusing System.Globalization;\n\nnamespace Captura\n{\n    public class TimeSpanToSecondsConverter : IValueConverter\n    {\n        public object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (Value is TimeSpan t)\n                return t.TotalSeconds;\n\n            return Binding.DoNothing;\n        }\n\n        public object ConvertBack(object Value, Type TargetType, object Parameter, CultureInfo Culture)\n        {\n            if (Value is double seconds)\n                return TimeSpan.FromSeconds(seconds);\n\n            return Binding.DoNothing;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/ValueConverters/ValueConverters.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:captura=\"clr-namespace:Captura\">\n    <captura:StateToRecordButtonGeometryConverter x:Key=\"StateToRecordButtonGeometryConverter\"/>\n    <captura:StateToTaskbarOverlayConverter x:Key=\"StateToTaskbarOverlayConverter\"/>\n    <captura:NotRecordingConverter x:Key=\"NotRecordingConverter\"/>\n    <captura:NotNullConverter x:Key=\"NotNullConverter\"/>\n    <captura:NegatingConverter x:Key=\"NegatingConverter\"/>\n    <captura:StateToTrayIconSourceConverter x:Key=\"StateToTrayIconSourceConverter\"/>\n    <captura:DrawingToWpfColorConverter x:Key=\"WpfColorConverter\"/>\n    <captura:InkToolToIconConverter x:Key=\"InkToolToIconConverter\"/>\n    <captura:TimeSpanToSecondsConverter x:Key=\"TimeSpanToSecondsConverter\"/>\n    <captura:SecondsToTimeSpanConverter x:Key=\"SecondsToTimeSpanConverter\"/>\n    <captura:IsPlayingToButtonStyleConverter x:Key=\"IsPlayingToButtonStyleConverter\"/>\n    <captura:IntegralTimeSpanConverter x:Key=\"IntegralTimeSpanConverter\"/>\n    <captura:GetTypeConverter x:Key=\"GetTypeConverter\"/>\n    <captura:StaticResourceConverter x:Key=\"StaticResourceConverter\"/>\n    <captura:IsLessThanConverter x:Key=\"IsLessThanConverter\"/>\n    <captura:LanguageConverter x:Key=\"LanguageConverter\"/>\n    <BooleanToVisibilityConverter x:Key=\"BoolToVisibilityConverter\"/>\n</ResourceDictionary>"
  },
  {
    "path": "src/Captura/ViewModels/AboutViewModel.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Windows.Input;\nusing Captura.Loc;\nusing Reactive.Bindings;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class AboutViewModel : ViewModelBase\n    {\n        public ICommand HyperlinkCommand { get; }\n\n        public static Version Version { get; }\n\n        public string AppVersion { get; }\n\n        static AboutViewModel()\n        {\n            Version = ServiceProvider.AppVersion;\n        }\n\n        public AboutViewModel(Settings Settings, ILocalizationProvider Loc) : base(Settings, Loc)\n        {\n            AppVersion = \"v\" + Version.ToString(3);\n\n            HyperlinkCommand = new ReactiveCommand<string>()\n                .WithSubscribe(M => Process.Start(M));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/ViewModels/ExceptionViewModel.cs",
    "content": "﻿using System;\nusing System.Collections.ObjectModel;\nusing System.Reactive.Linq;\nusing System.Text;\nusing System.Windows.Input;\nusing Captura.Models;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura\n{\n    public class ExceptionViewModel : NotifyPropertyChanged\n    {\n        public ExceptionViewModel()\n        {\n            CopyToClipboardCommand = Exceptions\n                .ObserveProperty(M => M.Count)\n                .Select(M => M > 0)\n                .ToReactiveCommand()\n                .WithSubscribe(OnCopyToClipboard);\n        }\n\n        void OnCopyToClipboard()\n        {\n            var sb = new StringBuilder();\n\n            sb.Append(SystemInfo.GetInfo());\n\n            sb.AppendLine();\n            sb.Append(Exceptions[0]);\n\n            sb.ToString().WriteToClipboard();\n        }\n\n        string _message = \"An unhandled exception occurred. Here are the details.\";\n\n        public string Message\n        {\n            get => _message;\n            set => Set(ref _message, value);\n        }\n\n        public void Init(Exception Exception, string Msg)\n        {\n            if (Msg != null)\n                Message = Msg;\n\n            while (Exception != null)\n            {\n                Exceptions.Add(Exception);\n\n                Exception = Exception.InnerException;\n            }\n\n            SelectedException = Exceptions[0];\n        }\n\n        public ObservableCollection<Exception> Exceptions { get; } = new ObservableCollection<Exception>();\n\n        Exception _selectedException;\n\n        public Exception SelectedException\n        {\n            get => _selectedException;\n            set => Set(ref _selectedException, value);\n        }\n\n        public ICommand CopyToClipboardCommand { get; }\n    }\n}"
  },
  {
    "path": "src/Captura/ViewModels/Overlays/CensorOverlayReactor.cs",
    "content": "﻿using System.Reactive.Linq;\nusing System.Windows;\nusing Captura.Video;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    public class CensorOverlayReactor\n    {\n        public CensorOverlayReactor(CensorOverlaySettings Settings)\n        {\n            Width = Settings\n                .ToReactivePropertyAsSynchronized(M => M.Width);\n\n            Height = Settings\n                .ToReactivePropertyAsSynchronized(M => M.Height);\n\n            Visible = Settings\n                .ObserveProperty(M => M.Display)\n                .Select(M => M ? Visibility.Visible : Visibility.Collapsed)\n                .ToReadOnlyReactivePropertySlim();\n        }\n\n        public IReactiveProperty<int> Width { get; }\n        public IReactiveProperty<int> Height { get; }\n\n        public IReadOnlyReactiveProperty<Visibility> Visible { get; }\n    }\n}"
  },
  {
    "path": "src/Captura/ViewModels/Overlays/ImageOverlayReactor.cs",
    "content": "﻿using System.Reactive.Linq;\nusing Captura.Video;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    public class ImageOverlayReactor\n    {\n        public ImageOverlayReactor(ImageOverlaySettings Settings)\n        {\n            Width = Settings\n                .ToReactivePropertyAsSynchronized(M => M.ResizeWidth);\n\n            Height = Settings\n                .ToReactivePropertyAsSynchronized(M => M.ResizeHeight);\n\n            Opacity = Settings\n                .ObserveProperty(M => M.Opacity)\n                .Select(M => M / 100.0)\n                .ToReadOnlyReactivePropertySlim();\n        }\n\n        public IReactiveProperty<int> Width { get; }\n        public IReactiveProperty<int> Height { get; }\n\n        public IReadOnlyReactiveProperty<double> Opacity { get; }\n    }\n}"
  },
  {
    "path": "src/Captura/ViewModels/Overlays/PositionOverlayReactor.cs",
    "content": "﻿using System.Reactive.Linq;\nusing System.Windows;\nusing Captura.Video;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    public class PositionOverlayReactor\n    {\n        public PositionOverlayReactor(PositionedOverlaySettings Settings)\n        {\n            HAlignment = Settings\n                .ObserveProperty(M => M.HorizontalAlignment)\n                .Select(M =>\n                {\n                    switch (M)\n                    {\n                        case Alignment.Start:\n                            return HorizontalAlignment.Left;\n\n                        case Alignment.Center:\n                            return HorizontalAlignment.Center;\n\n                        case Alignment.End:\n                            return HorizontalAlignment.Right;\n\n                        default:\n                            return HorizontalAlignment.Stretch;\n                    }\n                })\n                .ToReadOnlyReactivePropertySlim();\n\n            VAlignment = Settings\n                .ObserveProperty(M => M.VerticalAlignment)\n                .Select(M =>\n                {\n                    switch (M)\n                    {\n                        case Alignment.Start:\n                            return VerticalAlignment.Top;\n\n                        case Alignment.Center:\n                            return VerticalAlignment.Center;\n\n                        case Alignment.End:\n                            return VerticalAlignment.Bottom;\n\n                        default:\n                            return VerticalAlignment.Stretch;\n                    }\n                })\n                .ToReadOnlyReactivePropertySlim();\n\n            Margin = Settings\n                .ObserveProperty(M => M.HorizontalAlignment)\n                .CombineLatest(\n                    Settings\n                        .ObserveProperty(M => M.VerticalAlignment),\n                    Settings\n                        .ObserveProperty(M => M.X),\n                    Settings\n                        .ObserveProperty(M => M.Y),\n                    MarginPropSelector)\n                .ToReadOnlyReactivePropertySlim();\n        }\n\n        static Thickness MarginPropSelector(Alignment HAlign, Alignment VAlign, int X, int Y)\n        {\n            int left = 0, top = 0, right = 0, bottom = 0;\n\n            switch (HAlign)\n            {\n                case Alignment.Start:\n                case Alignment.Center:\n                    left = X;\n                    break;\n\n                case Alignment.End:\n                    right = X;\n                    break;\n            }\n\n            switch (VAlign)\n            {\n                case Alignment.Start:\n                case Alignment.Center:\n                    top = Y;\n                    break;\n\n                case Alignment.End:\n                    bottom = Y;\n                    break;\n            }\n\n            return new Thickness(left, top, right, bottom);\n        }\n\n        public IReadOnlyReactiveProperty<VerticalAlignment> VAlignment { get; }\n        public IReadOnlyReactiveProperty<HorizontalAlignment> HAlignment { get; }\n        public IReadOnlyReactiveProperty<Thickness> Margin { get; }\n    }\n}"
  },
  {
    "path": "src/Captura/ViewModels/Overlays/TextOverlayReactor.cs",
    "content": "﻿using System.Reactive.Linq;\nusing System.Windows;\nusing System.Windows.Media;\nusing Captura.Video;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    public class TextOverlayReactor\n    {\n        public TextOverlayReactor(TextOverlaySettings Settings)\n        {\n            FontFamily = Settings\n                .ObserveProperty(M => M.FontFamily)\n                .Select(M => new FontFamily(M))\n                .ToReadOnlyReactivePropertySlim();\n\n            FontSize = Settings\n                .ObserveProperty(M => M.FontSize)\n                .ToReadOnlyReactivePropertySlim();\n\n            Padding = new[]\n                {\n                    Settings\n                        .ObserveProperty(M => M.HorizontalPadding),\n                    Settings\n                        .ObserveProperty(M => M.VerticalPadding)\n                }\n                .CombineLatest(M =>\n                {\n                    var w = M[0];\n                    var h = M[1];\n\n                    return new Thickness(w, h, w, h);\n                })\n                .ToReadOnlyReactivePropertySlim();\n\n            Foreground = Settings\n                .ObserveProperty(M => M.FontColor)\n                .Select(M => new SolidColorBrush(M.ToWpfColor()))\n                .ToReadOnlyReactivePropertySlim();\n\n            Background = Settings\n                .ObserveProperty(M => M.BackgroundColor)\n                .Select(M => new SolidColorBrush(M.ToWpfColor()))\n                .ToReadOnlyReactivePropertySlim();\n\n            BorderThickness = Settings\n                .ObserveProperty(M => M.BorderThickness)\n                .Select(M => new Thickness(M))\n                .ToReadOnlyReactivePropertySlim();\n\n            BorderBrush = Settings\n                .ObserveProperty(M => M.BorderColor)\n                .Select(M => new SolidColorBrush(M.ToWpfColor()))\n                .ToReadOnlyReactivePropertySlim();\n\n            CornerRadius = Settings\n                .ObserveProperty(M => M.CornerRadius)\n                .Select(M => new CornerRadius(M))\n                .ToReadOnlyReactivePropertySlim();\n        }\n\n        public IReadOnlyReactiveProperty<FontFamily> FontFamily { get; }\n\n        public IReadOnlyReactiveProperty<int> FontSize { get; }\n\n        public IReadOnlyReactiveProperty<Thickness> Padding { get; }\n\n        public IReadOnlyReactiveProperty<Brush> Foreground { get; }\n\n        public IReadOnlyReactiveProperty<Brush> Background { get; }\n\n        public IReadOnlyReactiveProperty<Thickness> BorderThickness { get; }\n\n        public IReadOnlyReactiveProperty<Brush> BorderBrush { get; }\n\n        public IReadOnlyReactiveProperty<CornerRadius> CornerRadius { get; }\n    }\n}"
  },
  {
    "path": "src/Captura/ViewModels/Overlays/WebcamOverlayReactor.cs",
    "content": "﻿using System.Reactive.Linq;\nusing System.Reactive.Subjects;\nusing System.Windows;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\nusing Point = System.Drawing.Point;\n\nnamespace Captura.ViewModels\n{\n    public class WebcamOverlayReactor\n    {\n        public WebcamOverlayReactor(WebcamOverlaySettings Settings)\n        {\n            Location = Settings.ObserveProperty(M => M.XLoc)\n                .CombineLatest(\n                    Settings.ObserveProperty(M => M.YLoc),\n                    FrameSize,\n                    WebcamSize,\n                    Settings.ObserveProperty(M => M.Scale),\n                    (X, Y, FrameSize, WebcamSize, Scale) => Settings.GetPosition(FrameSize.ToDrawingSize(), WebcamSize.ToDrawingSize()))\n                .ToReadOnlyReactivePropertySlim();\n\n            Size = Settings.ObserveProperty(M => M.Scale)\n                .CombineLatest(\n                    FrameSize,\n                    WebcamSize,\n                    (Scale, FrameSize, WebcamSize) => Settings.GetSize(FrameSize.ToDrawingSize(), WebcamSize.ToDrawingSize()).ToWpfSize())\n                .ToReadOnlyReactivePropertySlim();\n\n            Opacity = Settings\n                .ObserveProperty(M => M.Opacity)\n                .Select(M => M / 100.0)\n                .ToReadOnlyReactivePropertySlim();\n        }\n\n        public Subject<Size> FrameSize { get; } = new Subject<Size>();\n\n        public Subject<Size> WebcamSize { get; } = new Subject<Size>();\n\n        public IReadOnlyReactiveProperty<Size> Size { get; }\n\n        public IReadOnlyReactiveProperty<double> Opacity { get; }\n\n        public IReadOnlyReactiveProperty<Point> Location { get; }\n    }\n}"
  },
  {
    "path": "src/Captura/ViewModels/RegionSelectorViewModel.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing Reactive.Bindings;\nusing Color = System.Windows.Media.Color;\n\n// ReSharper disable MemberCanBePrivate.Global\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class RegionSelectorViewModel : NotifyPropertyChanged\n    {\n        int _left = 50,\n            _top = 50,\n            _width = 500,\n            _height = 500;\n\n        const int MinWidth = 10,\n            MinHeight = 10,\n            KeyMoveDelta = 1;\n\n        public const int BorderSize = 3;\n\n        public RegionSelectorViewModel()\n        {\n            MoveLeftCommand = new ReactiveCommand()\n                .WithSubscribe(() => Left -= KeyMoveDelta);\n            MoveRightCommand = new ReactiveCommand()\n                .WithSubscribe(() => Left += KeyMoveDelta);\n            MoveUpCommand = new ReactiveCommand()\n                .WithSubscribe(() => Top -= KeyMoveDelta);\n            MoveDownCommand = new ReactiveCommand()\n                .WithSubscribe(() => Top += KeyMoveDelta);\n\n            IncreaseWidthCommand = new ReactiveCommand()\n                .WithSubscribe(() => Width += KeyMoveDelta);\n            DecreaseWidthCommand = new ReactiveCommand()\n                .WithSubscribe(() => Width -= KeyMoveDelta);\n            IncreaseHeightCommand = new ReactiveCommand()\n                .WithSubscribe(() => Height += KeyMoveDelta);\n            DecreaseHeightCommand = new ReactiveCommand()\n                .WithSubscribe(() => Height -= KeyMoveDelta);\n        }\n\n        public static Dictionary<InkCanvasEditingMode, string> Tools { get; } = new Dictionary<InkCanvasEditingMode, string>\n        {\n            [InkCanvasEditingMode.None] = \"Pointer\",\n            [InkCanvasEditingMode.Ink] = \"Pencil\",\n            [InkCanvasEditingMode.EraseByPoint] = \"Eraser\",\n            [InkCanvasEditingMode.EraseByStroke] = \"Stroke Eraser\"\n        };\n\n        public IReactiveProperty<InkCanvasEditingMode> SelectedTool { get; } = new ReactivePropertySlim<InkCanvasEditingMode>(Tools.Keys.First());\n\n        public IReactiveProperty<int> BrushSize { get; } = new ReactiveProperty<int>(10);\n\n        public IReactiveProperty<Color> BrushColor { get; } = new ReactiveProperty<Color>(Color.FromRgb(27, 27, 27));\n\n        public int Left\n        {\n            get => _left;\n            set\n            {\n                Set(ref _left, value);\n                RaisePropertyChanged(nameof(LeftDip));\n            }\n        }\n\n        public double LeftDip\n        {\n            get => Left / Dpi.X - BorderSize;\n            set => Left = (int)Math.Round((value + BorderSize) * Dpi.X);\n        }\n\n        public int Top\n        {\n            get => _top;\n            set\n            {\n                Set(ref _top, value);\n                RaisePropertyChanged(nameof(TopDip));\n            }\n        }\n\n        public double TopDip\n        {\n            get => Top / Dpi.Y - BorderSize;\n            set => Top = (int)Math.Round((value + BorderSize) * Dpi.Y);\n        }\n\n        public int Width\n        {\n            get => _width;\n            set\n            {\n                Set(ref _width, Math.Max(value, MinWidth));\n                RaisePropertyChanged(nameof(WidthDip));\n            }\n        }\n\n        public double WidthDip\n        {\n            get => Width / Dpi.X + 2 * BorderSize;\n            set => Width = (int)Math.Round((value - 2 * BorderSize) * Dpi.X);\n        }\n\n        public int Height\n        {\n            get => _height;\n            set\n            {\n                Set(ref _height, Math.Max(value, MinHeight));\n                RaisePropertyChanged(nameof(HeightDip));\n            }\n        }\n\n        public double HeightDip\n        {\n            get => Height / Dpi.Y + 2 * BorderSize;\n            set => Height = (int)Math.Round((value - 2 * BorderSize) * Dpi.Y);\n        }\n\n        public Rectangle SelectedRegion\n        {\n            get => new Rectangle(Left, Top, Width, Height);\n            set\n            {\n                Left = value.Left;\n                Top = value.Top;\n                Width = value.Width;\n                Height = value.Height;\n            }\n        }\n\n        public void ResizeFromTop(double VerticalChangeDip)\n        {\n            var verticalChange = (int) (VerticalChangeDip * Dpi.Y);\n\n            var oldBottom = Top + Height;\n            var top = Top + verticalChange;\n            \n            if (top <= 0)\n            {\n                Top = 0;\n                Height = oldBottom;\n                return;\n            }\n\n            var height = Height - verticalChange;\n\n            if (height > MinHeight)\n            {\n                Top = top;\n                Height = height;\n            }\n            else\n            {\n                Height = MinHeight;\n                Top = oldBottom - MinHeight;\n            }\n        }\n\n        public void ResizeFromLeft(double HorizontalChangeDip)\n        {\n            var horizontalChange = (int) (HorizontalChangeDip * Dpi.X);\n\n            var oldRight = Left + Width;\n            var left = Left + horizontalChange;\n\n            if (left <= 0)\n            {\n                Left = 0;\n                Width = oldRight;\n                return;\n            }\n\n            var width = Width - horizontalChange;\n\n            if (width > MinWidth)\n            {\n                Left = left;\n                Width = width;\n            }\n            else\n            {\n                Width = MinWidth;\n                Left = oldRight - MinWidth;\n            }\n        }\n\n        public ICommand MoveLeftCommand { get; }\n        public ICommand MoveRightCommand { get; }\n        public ICommand MoveUpCommand { get; }\n        public ICommand MoveDownCommand { get; }\n\n        public ICommand IncreaseWidthCommand { get; }\n        public ICommand DecreaseWidthCommand { get; }\n        public ICommand IncreaseHeightCommand { get; }\n        public ICommand DecreaseHeightCommand { get; }\n\n        public ReactiveCommand ClearAllDrawingsCommand { get; } = new ReactiveCommand();\n    }\n}"
  },
  {
    "path": "src/Captura/ViewModels/ScreenPickerViewModel.cs",
    "content": "﻿using System.IO;\nusing System.Windows;\nusing System.Windows.Media;\nusing System.Windows.Media.Imaging;\nusing Captura.Video;\n\nnamespace Captura.ViewModels\n{\n    public class ScreenPickerViewModel\n    {\n        public ScreenPickerViewModel(IScreen Screen, double Scale)\n        {\n            this.Screen = Screen;\n\n            using var bmp = ScreenShot.Capture(Screen.Rectangle);\n            var stream = new MemoryStream();\n            bmp.Save(stream, ImageFormats.Png);\n\n            stream.Seek(0, SeekOrigin.Begin);\n\n            var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default);\n            Image = new ImageBrush(decoder.Frames[0]);\n\n            Left = (Screen.Rectangle.Left / Dpi.X - SystemParameters.VirtualScreenLeft) * Scale;\n            Top = (Screen.Rectangle.Top / Dpi.Y - SystemParameters.VirtualScreenTop) * Scale;\n\n            Width = Screen.Rectangle.Width / Dpi.X * Scale;\n            Height = Screen.Rectangle.Height / Dpi.Y * Scale;\n        }\n\n        public double Left { get; }\n        public double Top { get; }\n\n        public double Width { get; }\n        public double Height { get; }\n\n        public IScreen Screen { get; }\n\n        public Brush Image { get; }\n    }\n}\n"
  },
  {
    "path": "src/Captura/ViewModels/TrimmerViewModel.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Reactive.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing System.Windows.Threading;\nusing Captura.FFmpeg;\nusing Microsoft.Win32;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura\n{\n    public class TrimmerViewModel : NotifyPropertyChanged, IDisposable\n    {\n        MediaElement _player;\n        readonly DispatcherTimer _timer;\n\n        public bool IsDragging { get; set; }\n\n        readonly IReactiveProperty<bool> _isOpened = new ReactivePropertySlim<bool>();\n        readonly IReactiveProperty<bool> _isTrimming = new ReactivePropertySlim<bool>();\n\n        public void AssignPlayer(MediaElement Player)\n        {\n            _player = Player;\n\n            _player.MediaOpened += (S, E) =>\n            {\n                From = TimeSpan.Zero;\n\n                if (_player.NaturalDuration.HasTimeSpan)\n                {\n                    To = End = _player.NaturalDuration.TimeSpan;\n                }\n                else To = End = TimeSpan.Zero;\n\n                PlaybackPosition = From;\n\n                _isOpened.Value = true;\n            };\n\n            _timer.Start();\n        }\n\n        public TrimmerViewModel()\n        {\n            _timer = new DispatcherTimer\n            {\n                Interval = TimeSpan.FromMilliseconds(100)\n            };\n\n            _timer.Tick += (Sender, Args) =>\n            {\n                if (IsDragging)\n                    return;\n\n                RaisePropertyChanged(nameof(PlaybackPosition));\n\n                if (IsPlaying && _player.Position > To || _player.Position < From)\n                {\n                    Stop();\n                }\n            };\n\n            OpenCommand = _isTrimming\n                .Select(M => !M)\n                .ToReactiveCommand()\n                .WithSubscribe(Open);\n\n            PlayCommand = new[]\n                {\n                    _isOpened,\n                    _isTrimming\n                        .Select(M => !M)\n                }\n                .CombineLatestValuesAreAllTrue()\n                .ToReactiveCommand()\n                .WithSubscribe(Play);\n\n            TrimCommand = new[]\n                {\n                    _isOpened,\n                    _isTrimming\n                        .Select(M => !M)\n                }\n                .CombineLatestValuesAreAllTrue()\n                .ToReactiveCommand()\n                .WithSubscribe(Trim);\n        }\n\n        TimeSpan _from, _to, _end;\n        \n        public TimeSpan From\n        {\n            get => _from;\n            set\n            {\n                _from = value;\n\n                if (IsPlaying && value + TimeSpan.FromSeconds(1) >= _player.Position)\n                {\n                    Stop();\n                }\n\n                if (!IsPlaying)\n                {\n                    PlaybackPosition = value;\n                }\n\n                OnPropertyChanged();\n            }\n        }\n\n        void Stop()\n        {\n            if (!_isPlaying)\n                return;\n\n            _player.Stop();\n\n            IsPlaying = false;\n\n            PlaybackPosition = From;\n        }\n\n        void Play()\n        {\n            if (IsPlaying)\n                Stop();\n            else\n            {\n                _player.Position = From;\n\n                _player.Play();\n\n                IsPlaying = true;\n            }\n        }\n\n        public TimeSpan To\n        {\n            get => _to;\n            set\n            {\n                _to = value;\n\n                if (IsPlaying && _player.Position + TimeSpan.FromSeconds(1) >= value)\n                {\n                    Stop();\n                }\n\n                if (!IsPlaying)\n                {\n                    PlaybackPosition = value;\n                }\n\n                OnPropertyChanged();\n            }\n        }\n\n        public TimeSpan End\n        {\n            get => _end;\n            set => Set(ref _end, value);\n        }\n\n        string _fileName;\n\n        public string FileName\n        {\n            get => _fileName;\n            private set => Set(ref _fileName, value);\n        }\n\n        string _filePath;\n\n        public string FilePath\n        {\n            get => _filePath;\n            set\n            {\n                _filePath = value;\n\n                FileName = Path.GetFileNameWithoutExtension(value);\n\n                OnPropertyChanged();\n            }\n        }\n\n        public ICommand OpenCommand { get; }\n\n        public ICommand PlayCommand { get; }\n\n        public ICommand TrimCommand { get; }\n\n        void Open()\n        {\n            var ofd = new OpenFileDialog\n            {\n                CheckPathExists = true,\n                CheckFileExists = true\n            };\n\n            if (ofd.ShowDialog().GetValueOrDefault())\n            {\n                Open(ofd.FileName);\n            }\n        }\n\n        public void Open(string Path)\n        {\n            _isOpened.Value = false;\n\n            _player.Source = new Uri(Path);\n\n            var oldVol = _player.Volume;\n\n            // Force Load\n            _player.Play();\n            _player.Stop();\n\n            _player.Volume = oldVol;\n\n            FilePath = Path;\n        }\n\n        bool _isPlaying;\n\n        public bool IsPlaying\n        {\n            get => _isPlaying;\n            set => Set(ref _isPlaying, value);\n        }\n\n        public TimeSpan PlaybackPosition\n        {\n            get => _player?.Position ?? TimeSpan.Zero;\n            set => _player.Position = value;\n        }\n\n        public void Dispose()\n        {\n            _player.Close();\n            _player.Source = null;\n        }\n\n        async void Trim()\n        {\n            if (!FFmpegService.FFmpegExists)\n            {\n                ServiceProvider.Get<IFFmpegViewsProvider>().ShowUnavailable();\n\n                return;\n            }\n\n            var ext = Path.GetExtension(FilePath);\n\n            var sfd = new SaveFileDialog\n            {\n                AddExtension = true,\n                DefaultExt = ext,\n                Filter = $\"*{ext}|*{ext}\",\n                FileName = Path.GetFileName(FilePath),\n                InitialDirectory = Path.GetDirectoryName(FilePath),\n                CheckPathExists = true\n            };\n\n            if (!sfd.ShowDialog().GetValueOrDefault())\n                return;\n\n            var hasAudio = _player.HasAudio;\n\n            _player.Close();\n\n            _isTrimming.Value = true;\n\n            var trimmer = new FFmpegTrimmer();\n\n            try\n            {\n                await trimmer.Run(FilePath,\n                    From,\n                    To,\n                    sfd.FileName,\n                    hasAudio);\n            }\n            finally\n            {\n                _isTrimming.Value = false;\n            }\n\n            MessageBox.Show(\"Done\");\n        }\n    }\n}"
  },
  {
    "path": "src/Captura/Windows/ErrorWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.Views.ErrorWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:captura=\"clr-namespace:Captura\"\n        mc:Ignorable=\"d\"\n        Title=\"{Binding ErrorOccurred, Source={StaticResource Loc}, Mode=OneWay}\"\n        SizeToContent=\"WidthAndHeight\"\n        ResizeMode=\"NoResize\"\n        WindowStartupLocation=\"CenterScreen\">\n    <Window.DataContext>\n        <captura:ExceptionViewModel/>\n    </Window.DataContext>\n    <Window.InputBindings>\n        <KeyBinding Key=\"C\"\n                    Modifiers=\"Control\"\n                    Command=\"{Binding CopyToClipboardCommand}\"/>\n    </Window.InputBindings>\n    <DockPanel Background=\"{DynamicResource WindowBackground}\"\n               MinWidth=\"400\">\n        <StackPanel DockPanel.Dock=\"Bottom\"\n                    Orientation=\"Horizontal\"\n                    HorizontalAlignment=\"Right\"\n                    Margin=\"5,15,5,5\">\n            <Button Click=\"OpenFFmpegLog\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.History, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"{Binding FFmpegLog, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                </DockPanel>\n            </Button>\n\n            <Button Margin=\"5,0\"\n                    Command=\"{Binding CopyToClipboardCommand}\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.Clipboard, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"{Binding CopyToClipboard, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                </DockPanel>\n            </Button>\n\n            <Button Content=\"View Details\"\n                    Click=\"ViewDetails_OnClick\"/>\n        </StackPanel>\n\n        <DockPanel DockPanel.Dock=\"Top\"\n                   Margin=\"10\">\n            <Path Data=\"{Binding Icons.Error, Source={StaticResource ServiceLocator}}\"\n                  Width=\"15\"\n                  Height=\"15\"\n                  Margin=\"0,0,10,0\"\n                  Stretch=\"Uniform\"\n                  HorizontalAlignment=\"Center\"\n                  VerticalAlignment=\"Center\"\n                  Fill=\"LightPink\"/>\n\n            <Label>\n                <TextBlock Text=\"{Binding Message}\"\n                           TextWrapping=\"Wrap\"/>\n            </Label>\n        </DockPanel>\n    </DockPanel>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/ErrorWindow.xaml.cs",
    "content": "﻿using System;\nusing System.Windows;\n\nnamespace Captura.Views\n{\n    public partial class ErrorWindow\n    {\n        readonly Exception _exception;\n        readonly string _message;\n\n        public ErrorWindow(Exception Exception, string Message = null)\n        {\n            _exception = Exception;\n            _message = Message;\n            InitializeComponent();\n\n            if (DataContext is ExceptionViewModel vm)\n            {\n                vm.Init(Exception, Message);\n            }\n        }\n\n        void ViewDetails_OnClick(object Sender, RoutedEventArgs E)\n        {\n            new ExceptionWindow(_exception, _message).ShowAndFocus();\n\n            Close();\n        }\n\n        void OpenFFmpegLog(object Sender, RoutedEventArgs E)\n        {\n            SettingsWindow.ShowFFmpegLogs();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/ExceptionWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.Views.ExceptionWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:captura=\"clr-namespace:Captura\"\n        mc:Ignorable=\"d\"\n        Title=\"{Binding ErrorOccurred, Source={StaticResource Loc}, Mode=OneWay}\"\n        Height=\"500\"\n        Width=\"700\">\n    <Window.DataContext>\n        <captura:ExceptionViewModel/>\n    </Window.DataContext>\n    <Window.InputBindings>\n        <KeyBinding Key=\"C\"\n                    Modifiers=\"Control\"\n                    Command=\"{Binding CopyToClipboardCommand}\"/>\n    </Window.InputBindings>\n    <DockPanel Background=\"{DynamicResource WindowBackground}\">\n        <DockPanel DockPanel.Dock=\"Top\"\n                   Margin=\"10\">\n            <Path Data=\"{Binding Icons.Error, Source={StaticResource ServiceLocator}}\"\n                  Width=\"15\"\n                  Height=\"15\"\n                  Margin=\"0,0,10,0\"\n                  Stretch=\"Uniform\"\n                  HorizontalAlignment=\"Center\"\n                  VerticalAlignment=\"Center\"\n                  Fill=\"LightPink\"/>\n\n            <Label>\n                <TextBlock Text=\"{Binding Message}\"\n                           TextWrapping=\"Wrap\"/>\n            </Label>\n        </DockPanel>\n\n        <StackPanel DockPanel.Dock=\"Bottom\"\n                    Orientation=\"Horizontal\"\n                    HorizontalAlignment=\"Right\">\n            <Button Click=\"OpenFFmpegLog\"\n                    Margin=\"0,5\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.History, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"{Binding FFmpegLog, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                </DockPanel>\n            </Button>\n            \n            <Button Margin=\"5\"\n                    Command=\"{Binding CopyToClipboardCommand}\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.Clipboard, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"{Binding CopyToClipboard, Source={StaticResource Loc}, Mode=OneWay}\"/>\n                </DockPanel>\n            </Button>\n            <Button Content=\"{Binding Close, Source={StaticResource Loc}, Mode=OneWay}\"\n                    Margin=\"5\"\n                    Click=\"Close_OnClick\"/>\n        </StackPanel>\n        \n        <Grid Margin=\"5\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"200\"/>\n                <ColumnDefinition Width=\"Auto\"/>\n                <ColumnDefinition Width=\"*\"/>\n            </Grid.ColumnDefinitions>\n            \n            <ListView ItemsSource=\"{Binding Exceptions}\"\n                      SelectedValue=\"{Binding SelectedException, Mode=TwoWay}\"\n                      Padding=\"5,0\">\n                <ListView.ItemTemplate>\n                    <DataTemplate>\n                        <TextBlock Text=\"{Binding Converter={StaticResource GetTypeConverter}, Mode=OneWay}\"/>\n                    </DataTemplate>\n                </ListView.ItemTemplate>\n            </ListView>\n            \n            <GridSplitter Width=\"2\"\n                          Margin=\"10,0\"\n                          Grid.Column=\"1\"/>\n\n            <ScrollViewer Grid.Column=\"2\"\n                          HorizontalScrollBarVisibility=\"Auto\">\n                <StackPanel>\n                    <Label>\n                        <TextBlock Style=\"{StaticResource Title}\"\n                                   Text=\"{Binding SelectedException, Converter={StaticResource GetTypeConverter}}\"/>\n                    </Label>\n                    \n                    <Label FontWeight=\"Bold\"\n                           Content=\"Message\"\n                           Visibility=\"{Binding SelectedException.Message, Converter={StaticResource NotNullConverter}}\"\n                           Margin=\"0,10,0,0\"/>\n                    \n                    <Label Content=\"{Binding SelectedException.Message}\"\n                           Visibility=\"{Binding SelectedException.Message, Converter={StaticResource NotNullConverter}}\"/>\n\n                    <Label FontWeight=\"Bold\"\n                           Content=\"Stack Trace\"\n                           Visibility=\"{Binding SelectedException.StackTrace, Converter={StaticResource NotNullConverter}}\"\n                           Margin=\"0,10,0,0\"/>\n\n                    <Label Content=\"{Binding SelectedException.StackTrace}\"\n                           Visibility=\"{Binding SelectedException.StackTrace, Converter={StaticResource NotNullConverter}}\"/>\n\n                    <Label FontWeight=\"Bold\"\n                           Content=\"Data\"\n                           Visibility=\"{Binding SelectedException.Data, Converter={StaticResource NotNullConverter}}\"\n                           Margin=\"0,10,0,0\"/>\n\n                    <ItemsControl ItemsSource=\"{Binding SelectedException.Data}\"\n                                  Visibility=\"{Binding SelectedException.Data, Converter={StaticResource NotNullConverter}}\">\n                        <ItemsControl.ItemTemplate>\n                            <DataTemplate>\n                                <Label>\n                                    <TextBlock FontStyle=\"Italic\">\n                                        <Run Text=\"{Binding Key, Mode=OneWay}\"/> = <Run Text=\"{Binding Value, Mode=OneWay}\"/>\n                                    </TextBlock>\n                                </Label>\n                            </DataTemplate>\n                        </ItemsControl.ItemTemplate>\n                    </ItemsControl>\n\n                    <Label FontWeight=\"Bold\"\n                           Content=\"Target Site\"\n                           Visibility=\"{Binding SelectedException.TargetSite, Converter={StaticResource NotNullConverter}}\"\n                           Margin=\"0,10,0,0\"/>\n\n                    <Label Content=\"{Binding SelectedException.TargetSite}\"\n                           Visibility=\"{Binding SelectedException.TargetSite, Converter={StaticResource NotNullConverter}}\"/>\n\n                    <Label FontWeight=\"Bold\"\n                           Content=\"Source\"\n                           Visibility=\"{Binding SelectedException.Source, Converter={StaticResource NotNullConverter}}\"\n                           Margin=\"0,10,0,0\"/>\n\n                    <Label Content=\"{Binding SelectedException.Source}\"\n                           Visibility=\"{Binding SelectedException.Source, Converter={StaticResource NotNullConverter}}\"/>\n\n                    <Label FontWeight=\"Bold\"\n                           Content=\"Help Link\"\n                           Visibility=\"{Binding SelectedException.HelpLink, Converter={StaticResource NotNullConverter}}\"\n                           Margin=\"0,10,0,0\"/>\n\n                    <Label Content=\"{Binding SelectedException.HelpLink}\"\n                           Visibility=\"{Binding SelectedException.HelpLink, Converter={StaticResource NotNullConverter}}\"/>\n\n                    <Label FontWeight=\"Bold\"\n                           Content=\"HResult\"\n                           Margin=\"0,10,0,0\"/>\n\n                    <Label Content=\"{Binding SelectedException.HResult}\"/>\n                </StackPanel>\n            </ScrollViewer>\n        </Grid>\n    </DockPanel>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/ExceptionWindow.xaml.cs",
    "content": "﻿using System;\nusing System.Windows;\n\nnamespace Captura.Views\n{\n    public partial class ExceptionWindow\n    {\n        public ExceptionWindow(Exception Exception, string Message = null)\n        {\n            InitializeComponent();\n\n            if (DataContext is ExceptionViewModel vm)\n            {\n                vm.Init(Exception, Message);\n            }\n        }\n\n        void Close_OnClick(object Sender, RoutedEventArgs E)\n        {\n            Close();\n        }\n\n        void OpenFFmpegLog(object Sender, RoutedEventArgs E)\n        {\n            SettingsWindow.ShowFFmpegLogs();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/FFmpegDownloaderWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.Views.FFmpegDownloaderWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:local=\"clr-namespace:Captura\"\n        xmlns:mui=\"http://firstfloorsoftware.com/ModernUI\"\n        Title=\"FFmpeg Downloader\"\n        Height=\"400\"\n        Width=\"600\"\n        ResizeMode=\"NoResize\"\n        Background=\"{DynamicResource WindowBackground}\"\n        DataContext=\"{Binding FFmpegDownloadViewModel, Source={StaticResource ServiceLocator}}\">\n    <WindowChrome.WindowChrome>\n        <WindowChrome GlassFrameThickness=\"1\"\n                      UseAeroCaptionButtons=\"False\"\n                      NonClientFrameEdges=\"None\"\n                      CaptionHeight=\"40\"/>\n    </WindowChrome.WindowChrome>\n    <Window.TaskbarItemInfo>\n        <TaskbarItemInfo/>\n    </Window.TaskbarItemInfo>\n    <DockPanel Margin=\"5\">\n        <DockPanel DockPanel.Dock=\"Top\">\n            <local:ModernButton ToolTip=\"{Binding Close, Source={StaticResource Loc}, Mode=OneWay}\"\n                                Click=\"CloseButton_Click\"\n                                IconData=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"\n                                DockPanel.Dock=\"Right\"\n                                WindowChrome.IsHitTestVisibleInChrome=\"True\"/>\n            <Label Content=\"FFmpeg Downloader\"\n                   Margin=\"10,0\"/>\n        </DockPanel>\n        \n        <DockPanel DockPanel.Dock=\"Top\"\n                   Margin=\"15\">\n            <Label Margin=\"0,0,10,0\"\n                   Content=\"Download Progress\"\n                   ContentStringFormat=\"{}{0}:\"/>\n            <ProgressBar Value=\"{Binding Progress.Value, Mode=OneWay}\"\n                         Height=\"10\"/>\n        </DockPanel>\n\n        <Label Content=\"{Binding Status.Value}\"\n               DockPanel.Dock=\"Top\"\n               Margin=\"0,10\"\n               HorizontalAlignment=\"Center\"\n               ContentStringFormat=\"{}Status: {0}\"/>\n\n        <DockPanel DockPanel.Dock=\"Bottom\"\n                   Margin=\"0,5\">\n            <Button Command=\"{Binding OpenFolderCommand}\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.Folder, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"Target Folder:\"/>\n                </DockPanel>\n            </Button>\n\n            <Button DockPanel.Dock=\"Right\"\n                    Command=\"{Binding SelectFolderCommand}\">\n                <Path Stretch=\"UniformToFill\"\n                      Height=\"4\"\n                      Width=\"16\"\n                      Data=\"{Binding Icons.More, Source={StaticResource ServiceLocator}}\"/>\n            </Button>\n            <Border ToolTip=\"{Binding FFmpegSettings.FolderPath, Mode=OneWay}\"\n                    MouseUp=\"SelectTargetFolder\">\n                <TextBox IsReadOnly=\"True\"\n                         IsEnabled=\"False\"\n                         Text=\"{Binding FFmpegSettings.FolderPath, Mode=OneWay}\"/>\n            </Border>\n        </DockPanel>\n\n        <TextBlock DockPanel.Dock=\"Bottom\"\n                   Margin=\"0,5\"\n                   HorizontalAlignment=\"Center\"\n                   Style=\"{StaticResource TextColor}\"\n                   Opacity=\"0.9\">\n            FFmpeg adds support for more output formats to Captura.<LineBreak/>\n            Latest build of FFmpeg is downloaded. This can also be used to update FFmpeg.<LineBreak/>\n            The Download size is nearly 70 MB.\n        </TextBlock>\n\n        <Grid HorizontalAlignment=\"Center\"\n              Margin=\"0,10\"\n              DockPanel.Dock=\"Top\">\n            <Button Content=\"Start Download\"\n                    Command=\"{Binding StartCommand}\"\n                    Visibility=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={StaticResource BoolToVisibilityConverter}}\"/>\n            <Button Content=\"Cancel Download\"\n                    IsEnabled=\"{Binding CanCancel.Value}\"\n                    Click=\"CloseButton_Click\"\n                    Visibility=\"{Binding InProgress.Value, Converter={StaticResource BoolToVisibilityConverter}}\"/>\n            <Button Content=\"Finish\"\n                    IsEnabled=\"{Binding IsDone.Value}\"\n                    Click=\"CloseButton_Click\"\n                    Visibility=\"{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={StaticResource BoolToVisibilityConverter}}\"/>\n        </Grid>\n        \n        <mui:ModernProgressRing IsActive=\"{Binding InProgress.Value}\"/>\n    </DockPanel>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/FFmpegDownloaderWindow.xaml.cs",
    "content": "﻿using System.Windows;\nusing System.Windows.Input;\nusing System.Windows.Shell;\nusing Captura.ViewModels;\n\nnamespace Captura.Views\n{\n    public partial class FFmpegDownloaderWindow\n    {\n        FFmpegDownloaderWindow()\n        {\n            InitializeComponent();\n\n            if (DataContext is FFmpegDownloadViewModel vm)\n            {\n                Closing += async (S, E) =>\n                {\n                    if (!await vm.Cancel())\n                    {\n                        E.Cancel = true;\n                    }\n                };\n\n                vm.ProgressChanged += P =>\n                {\n                    Dispatcher.Invoke(() =>\n                    {\n                        TaskbarItemInfo.ProgressState = TaskbarItemProgressState.Normal;\n                        TaskbarItemInfo.ProgressValue = P / 100.0;\n                    });\n                };\n\n                vm.AfterDownload += Success =>\n                {\n                    Dispatcher.Invoke(() =>\n                    {\n                        TaskbarItemInfo.ProgressState = Success ? TaskbarItemProgressState.None : TaskbarItemProgressState.Error;\n                        TaskbarItemInfo.ProgressValue = 1;\n                    });\n                };\n            }\n        }\n\n        void CloseButton_Click(object Sender, RoutedEventArgs E) => Close();\n\n        void SelectTargetFolder(object Sender, MouseButtonEventArgs E)\n        {\n            if (DataContext is FFmpegDownloadViewModel vm)\n            {\n                vm.SelectFolderCommand.ExecuteIfCan();\n            }\n        }\n\n        static FFmpegDownloaderWindow _downloader;\n\n        public static void ShowInstance()\n        {\n            if (_downloader == null)\n            {\n                _downloader = new FFmpegDownloaderWindow();\n                _downloader.Closed += (Sender, Args) => _downloader = null;\n            }\n\n            _downloader.ShowAndFocus();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/MainWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.MainWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:tb=\"http://www.hardcodet.net/taskbar\"\n        xmlns:local=\"clr-namespace:Captura\"\n        DataContext=\"{Binding MainViewModel, Source={StaticResource ServiceLocator}}\"\n        ResizeMode=\"CanMinimize\"\n        Icon=\"../Images/Captura.ico\"\n        SizeToContent=\"Height\"\n        MaxWidth=\"440\"\n        Title=\"Captura\"\n        Left=\"{Binding Settings.UI.MainWindowLeft, Mode=TwoWay}\"\n        Top=\"{Binding Settings.UI.MainWindowTop, Mode=TwoWay}\"\n        BorderThickness=\"1\"\n        BorderBrush=\"{DynamicResource Accent}\"\n        Topmost=\"{Binding Settings.UI.MainWindowTopmost}\">\n    <WindowChrome.WindowChrome>\n        <WindowChrome GlassFrameThickness=\"1\"\n                      UseAeroCaptionButtons=\"False\"\n                      NonClientFrameEdges=\"None\"\n                      CaptionHeight=\"0\"/>\n    </WindowChrome.WindowChrome>\n    <Window.TaskbarItemInfo>\n        <TaskbarItemInfo Overlay=\"{Binding RecordingViewModel.RecorderState.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource StateToTaskbarOverlayConverter}}\"\n                         Description=\"Captura\">\n            <TaskbarItemInfo.ThumbButtonInfos>\n                <ThumbButtonInfo Command=\"{Binding ScreenShotViewModel.ScreenShotCommand, Source={StaticResource ServiceLocator}}\"\n                                 Description=\"{Binding ScreenShot, Source={StaticResource Loc}, Mode=OneWay}\"\n                                 DismissWhenClicked=\"True\"\n                                 ImageSource=\"{StaticResource ScreenShotImageSource}\"/>\n                <ThumbButtonInfo Command=\"{Binding RecordingViewModel.RecordCommand, Source={StaticResource ServiceLocator}}\"\n                                 Description=\"{Binding RecordStop, Source={StaticResource Loc}, Mode=OneWay}\"\n                                 DismissWhenClicked=\"True\"\n                                 ImageSource=\"{StaticResource RecordStopImageSource}\"/>\n            </TaskbarItemInfo.ThumbButtonInfos>\n        </TaskbarItemInfo>\n    </Window.TaskbarItemInfo>\n    <Grid Background=\"{DynamicResource WindowBackground}\">\n        <Grid.RowDefinitions>\n            <RowDefinition/>\n            <RowDefinition Height=\"Auto\"/>\n        </Grid.RowDefinitions>\n\n        <!-- NotifyIcon -->\n        <tb:TaskbarIcon x:Name=\"SystemTray\"\n                        IconSource=\"{Binding RecordingViewModel.RecorderState.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource StateToTrayIconSourceConverter}}\"\n                        ToolTipText=\"Captura\"\n                        MenuActivation=\"RightClick\"\n                        LeftClickCommand=\"{Binding TrayLeftClickCommand}\"\n                        TrayMouseDoubleClick=\"SystemTray_TrayMouseDoubleClick\">\n            <tb:TaskbarIcon.ContextMenu>\n                <ContextMenu>\n                    <MenuItem Header=\"{Binding StartStopRecording, Source={StaticResource Loc}, Mode=OneWay}\"\n                              Command=\"{Binding RecordingViewModel.RecordCommand, Source={StaticResource ServiceLocator}}\">\n                        <MenuItem.Icon>\n                            <Image Source=\"{StaticResource RecordStopImageSource}\"\n                                   Width=\"13\"\n                                   Margin=\"5\"/>\n                        </MenuItem.Icon>\n                    </MenuItem>\n\n                    <MenuItem Header=\"{Binding PauseResumeRecording, Source={StaticResource Loc}, Mode=OneWay}\"\n                              Command=\"{Binding RecordingViewModel.PauseCommand, Source={StaticResource ServiceLocator}}\">\n                        <MenuItem.Icon>\n                            <Image Width=\"10\"\n                                   Margin=\"5\">\n                                <Image.Source>\n                                    <DrawingImage>\n                                        <DrawingImage.Drawing>\n                                            <GeometryDrawing Geometry=\"{Binding Icons.Pause, Source={StaticResource ServiceLocator}}\"\n                                                             Brush=\"{DynamicResource ItemText}\"/>\n                                        </DrawingImage.Drawing>\n                                    </DrawingImage>\n                                </Image.Source>\n                                <Image.Style>\n                                    <Style TargetType=\"Image\">\n                                        <Style.Triggers>\n                                            <DataTrigger Binding=\"{Binding RecordingViewModel.RecorderState.Value, Source={StaticResource ServiceLocator}}\" Value=\"Paused\">\n                                                <Setter Property=\"LayoutTransform\">\n                                                    <Setter.Value>\n                                                        <RotateTransform Angle=\"90\"/>\n                                                    </Setter.Value>\n                                                </Setter>\n                                            </DataTrigger>\n                                        </Style.Triggers>\n                                    </Style>\n                                </Image.Style>\n                            </Image>\n                        </MenuItem.Icon>\n                    </MenuItem>\n\n                    <Separator/>\n\n                    <MenuItem Header=\"{Binding ScreenShot, Source={StaticResource Loc}, Mode=OneWay}\"\n                              Command=\"{Binding ScreenShotViewModel.ScreenShotCommand, Source={StaticResource ServiceLocator}}\">\n                        <MenuItem.Icon>\n                            <Image Source=\"{StaticResource ScreenShotImageSource}\"\n                                   Width=\"13\"\n                                   Margin=\"5\"/>\n                        </MenuItem.Icon>\n                    </MenuItem>\n\n                    <MenuItem Header=\"{Binding ScreenShotDesktop, Source={StaticResource Loc}, Mode=OneWay}\"\n                              Command=\"{Binding ScreenShotViewModel.ScreenShotDesktopCommand, Source={StaticResource ServiceLocator}}\">\n                        <MenuItem.Icon>\n                            <Image Source=\"{StaticResource ScreenShotImageSource}\"\n                                   Width=\"13\"\n                                   Margin=\"5\"/>\n                        </MenuItem.Icon>\n                    </MenuItem>\n                    \n                    <Separator/>\n\n                    <MenuItem Header=\"ScreenShot (Region)\"\n                              Command=\"{Binding ScreenShotViewModel.ScreenshotRegionCommand, Source={StaticResource ServiceLocator}}\">\n                        <MenuItem.Icon>\n                            <Image Width=\"13\"\n                                   Margin=\"5\">\n                                <Image.Source>\n                                    <DrawingImage>\n                                        <DrawingImage.Drawing>\n                                            <GeometryDrawing Geometry=\"{Binding Icons.Crop, Source={StaticResource ServiceLocator}}\"\n                                                             Brush=\"{DynamicResource ItemText}\"/>\n                                        </DrawingImage.Drawing>\n                                    </DrawingImage>\n                                </Image.Source>\n                            </Image>\n                        </MenuItem.Icon>\n                    </MenuItem>\n                      \n                    <MenuItem Header=\"ScreenShot (Screen)\"\n                              Command=\"{Binding ScreenShotViewModel.ScreenshotScreenCommand, Source={StaticResource ServiceLocator}}\">\n                        <MenuItem.Icon>\n                            <Image Width=\"13\"\n                                   Margin=\"5\">\n                                <Image.Source>\n                                    <DrawingImage>\n                                        <DrawingImage.Drawing>\n                                            <GeometryDrawing Geometry=\"{Binding Icons.Screen, Source={StaticResource ServiceLocator}}\"\n                                                             Brush=\"{DynamicResource ItemText}\"/>\n                                        </DrawingImage.Drawing>\n                                    </DrawingImage>\n                                </Image.Source>\n                            </Image>\n                        </MenuItem.Icon>\n                    </MenuItem>\n\n                    <MenuItem Header=\"ScreenShot (Window)\"\n                              Command=\"{Binding ScreenShotViewModel.ScreenshotWindowCommand, Source={StaticResource ServiceLocator}}\">\n                        <MenuItem.Icon>\n                            <Image Width=\"13\"\n                                   Margin=\"5\">\n                                <Image.Source>\n                                    <DrawingImage>\n                                        <DrawingImage.Drawing>\n                                            <GeometryDrawing Geometry=\"{Binding Icons.Window, Source={StaticResource ServiceLocator}}\"\n                                                             Brush=\"{DynamicResource ItemText}\"/>\n                                        </DrawingImage.Drawing>\n                                    </DrawingImage>\n                                </Image.Source>\n                            </Image>\n                        </MenuItem.Icon>\n                    </MenuItem>\n\n                    <Separator/>\n\n                    <MenuItem Header=\"Show Main Window\"\n                              Click=\"ShowMainWindow\">\n                        <MenuItem.Icon>\n                            <Image Width=\"13\"\n                                   Margin=\"5\">\n                                <Image.Source>\n                                    <DrawingImage>\n                                        <DrawingImage.Drawing>\n                                            <GeometryDrawing Geometry=\"{Binding Icons.Window, Source={StaticResource ServiceLocator}}\"\n                                                             Brush=\"{DynamicResource ItemText}\"/>\n                                        </DrawingImage.Drawing>\n                                    </DrawingImage>\n                                </Image.Source>\n                            </Image>\n                        </MenuItem.Icon>\n                    </MenuItem>\n\n                    <MenuItem Header=\"{Binding Exit, Source={StaticResource Loc}, Mode=OneWay}\"\n                              Click=\"MenuExit_Click\">\n                        <MenuItem.Icon>\n                            <Image Width=\"13\"\n                                   Margin=\"5\">\n                                <Image.Source>\n                                    <DrawingImage>\n                                        <DrawingImage.Drawing>\n                                            <GeometryDrawing Geometry=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"\n                                                             Brush=\"#b71c1c\"/>\n                                        </DrawingImage.Drawing>\n                                    </DrawingImage>\n                                </Image.Source>\n                            </Image>\n                        </MenuItem.Icon>\n                    </MenuItem>\n                </ContextMenu>\n            </tb:TaskbarIcon.ContextMenu>\n        </tb:TaskbarIcon>\n\n        <Expander Padding=\"5,0,0,0\"\n                  Grid.Row=\"0\"\n                  IsExpanded=\"{Binding Settings.UI.Expanded}\">\n            <Expander.Header>\n                <Grid>\n                    <Border CornerRadius=\"15,15,25,25\"\n                            BorderThickness=\"0\"\n                            Margin=\"0,2,0,0\"\n                            HorizontalAlignment=\"Left\"\n                            VerticalAlignment=\"Top\"\n                            Width=\"70\"\n                            Height=\"33\"\n                            Background=\"{DynamicResource ButtonBackgroundHover}\"/>\n                    <DockPanel VerticalAlignment=\"Center\">\n                        <local:CollapsedBar DockPanel.Dock=\"Bottom\"\n                                            Margin=\"-30,0,0,0\"/>\n\n                        <local:ScreenShotButton/>\n                        <local:ModernButton ToolTip=\"{Binding RecordStop, Source={StaticResource Loc}, Mode=OneWay}\"\n                                            Command=\"{Binding RecordingViewModel.RecordCommand, Source={StaticResource ServiceLocator}}\"\n                                            Foreground=\"#ee2c2c\"\n                                            IconData=\"{Binding RecordingViewModel.RecorderState.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource StateToRecordButtonGeometryConverter}}\"/>\n                        <local:PauseButton/>\n                        <local:ModernButton ToolTip=\"{Binding Close, Source={StaticResource Loc}, Mode=OneWay}\"\n                                            Click=\"CloseButton_Click\"\n                                            Foreground=\"#77ef5350\"\n                                            IconData=\"{Binding Icons.Close, Source={StaticResource ServiceLocator}}\"\n                                            DockPanel.Dock=\"Right\"/>\n                        <local:ModernButton ToolTip=\"{Binding MinTray, Source={StaticResource Loc}, Mode=OneWay}\"\n                                            Click=\"HideButton_Click\"\n                                            IconData=\"{Binding Icons.DoubleDown, Source={StaticResource ServiceLocator}}\"\n                                            Opacity=\"0.7\"\n                                            DockPanel.Dock=\"Right\"/>\n                        <local:ModernButton ToolTip=\"{Binding Minimize, Source={StaticResource Loc}, Mode=OneWay}\"\n                                            Click=\"MinButton_Click\"\n                                            IconData=\"{Binding Icons.Minimize, Source={StaticResource ServiceLocator}}\"\n                                            Opacity=\"0.7\"\n                                            DockPanel.Dock=\"Right\"/>\n\n                        <Grid Margin=\"0,-2\"\n                              PreviewMouseLeftButtonDown=\"Grid_PreviewMouseLeftButtonDown\"\n                              Background=\"#01000000\">\n                            <Border CornerRadius=\"15\"\n                                    BorderThickness=\"0\"\n                                    Margin=\"30,5\"\n                                    Background=\"{DynamicResource ButtonBackgroundHover}\"/>\n\n                            <StackPanel Margin=\"10,-1\"\n                                        Visibility=\"{Binding TimerModel.Countdown, Source={StaticResource ServiceLocator}, Converter={StaticResource IsLessThanConverter}, ConverterParameter=1}\"\n                                        Name=\"DurationLabel\"\n                                        HorizontalAlignment=\"Center\"\n                                        VerticalAlignment=\"Center\">\n                                <Label Content=\"{Binding TimerModel.TimeSpan, Source={StaticResource ServiceLocator}}\"/>\n\n                                <Label Content=\"{Binding Settings.Duration, Converter={StaticResource SecondsToTimeSpanConverter}}\"\n                                       ContentStringFormat=\"{}{0}\"\n                                       HorizontalAlignment=\"Center\"\n                                       FontSize=\"8\"\n                                       Visibility=\"{Binding Settings.Duration, Converter={StaticResource NotNullConverter}}\"/>\n                            </StackPanel>\n\n                            <Label Visibility=\"{Binding Visibility, ElementName=DurationLabel, Converter={StaticResource NegatingConverter}}\"\n                                   Margin=\"0,-1\"\n                                   Style=\"{StaticResource CountdownLabel}\"\n                                   HorizontalAlignment=\"Center\"\n                                   Content=\"{Binding TimerModel.Countdown, Source={StaticResource ServiceLocator}}\"/>\n                        </Grid>\n                    </DockPanel>\n                </Grid>\n            </Expander.Header>\n            <DockPanel Margin=\"-5,0\"\n                       Height=\"300\">\n                <Frame Source=\"../Pages/MainPage.xaml\"\n                       DockPanel.Dock=\"Top\"/>\n\n                <GridSplitter Height=\"1\"\n                              Margin=\"0,2\"\n                              DockPanel.Dock=\"Top\"\n                              IsEnabled=\"False\"/>\n\n                <Label DockPanel.Dock=\"Bottom\"\n                       Margin=\"5,0\"\n                       Visibility=\"{Binding ViewConditions.FpsVisibility.Value, Source={StaticResource ServiceLocator}}\">\n                    <TextBlock>\n                        FPS: <Run Text=\"{Binding FpsManager.Fps, Source={StaticResource ServiceLocator}, Mode=OneWay}\"/>\n                    </TextBlock>\n                </Label>\n\n                <GridSplitter Height=\"1\"\n                              Margin=\"0,2\"\n                              DockPanel.Dock=\"Bottom\"\n                              IsEnabled=\"False\"/>\n\n                <Grid xmlns:wf=\"clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms\"\n                      xmlns:interop=\"clr-namespace:System.Windows.Interop;assembly=PresentationCore\">\n                    <Label Content=\"Preview\"\n                           HorizontalAlignment=\"Center\"\n                           Opacity=\"0.7\"/>\n                    <WindowsFormsHost Name=\"WinFormsHost\"\n                                      Visibility=\"Collapsed\">\n                        <wf:PictureBox x:Name=\"DisplayImage\"\n                                       SizeMode=\"Zoom\"/>\n                    </WindowsFormsHost>\n                    <Image>\n                        <Image.Source>\n                            <interop:D3DImage x:Name=\"D3DImage\"/>\n                        </Image.Source>\n                    </Image>\n                </Grid>\n            </DockPanel>\n        </Expander>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/MainWindow.xaml.cs",
    "content": "﻿using System.Drawing;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Forms;\nusing System.Windows.Input;\nusing Captura.Models;\n\nnamespace Captura\n{\n    public partial class MainWindow\n    {\n        public static MainWindow Instance { get; private set; }\n\n        readonly MainWindowHelper _helper;\n\n        public MainWindow()\n        {\n            Instance = this;\n            \n            InitializeComponent();\n\n            _helper = ServiceProvider.Get<MainWindowHelper>();\n\n            _helper.MainViewModel.Init(!App.CmdOptions.NoPersist, !App.CmdOptions.Reset);\n\n            _helper.HotkeySetup.Setup();\n\n            _helper.TimerModel.Init();\n\n            Loaded += (Sender, Args) =>\n            {\n                RepositionWindowIfOutside();\n\n                ServiceProvider.Get<WebcamPage>().SetupPreview();\n\n                _helper.HotkeySetup.ShowUnregistered();\n            };\n\n            if (App.CmdOptions.Tray || _helper.Settings.Tray.MinToTrayOnStartup)\n                Hide();\n\n            Closing += (Sender, Args) =>\n            {\n                if (!TryExit())\n                    Args.Cancel = true;\n            };\n\n            // Register to bring this instance to foreground when other instances are launched.\n            SingleInstanceManager.StartListening(WakeApp);\n        }\n\n        void WakeApp()\n        {\n            Dispatcher.Invoke(() =>\n            {\n                if (WindowState == WindowState.Minimized)\n                {\n                    WindowState = WindowState.Normal;\n                }\n\n                Activate();\n            });\n        }\n\n        void RepositionWindowIfOutside()\n        {\n            // Window dimensions taking care of DPI\n            var rect = new RectangleF((float) Left,\n                (float) Top,\n                (float) ActualWidth,\n                (float) ActualHeight).ApplyDpi();\n            \n            if (!Screen.AllScreens.Any(M => M.Bounds.Contains(rect)))\n            {\n                Left = 50;\n                Top = 50;\n            }\n        }\n\n        void Grid_PreviewMouseLeftButtonDown(object Sender, MouseButtonEventArgs Args)\n        {\n            DragMove();\n\n            Args.Handled = true;\n        }\n\n        void MinButton_Click(object Sender, RoutedEventArgs Args) => SystemCommands.MinimizeWindow(this);\n\n        void CloseButton_Click(object Sender, RoutedEventArgs Args)\n        {\n            if (_helper.Settings.Tray.MinToTrayOnClose)\n            {\n                Hide();\n            }\n            else Close();\n        }\n\n        void SystemTray_TrayMouseDoubleClick(object Sender, RoutedEventArgs Args)\n        {\n            if (Visibility == Visibility.Visible)\n            {\n                Hide();\n            }\n            else this.ShowAndFocus();\n        }\n\n        bool TryExit()\n        {\n            if (!_helper.RecordingViewModel.CanExit())\n                return false;\n\n            ServiceProvider.Dispose();\n\n            return true;\n        }\n\n        void MenuExit_Click(object Sender, RoutedEventArgs Args) => Close();\n\n        void HideButton_Click(object Sender, RoutedEventArgs Args) => Hide();\n\n        void ShowMainWindow(object Sender, RoutedEventArgs E) => this.ShowAndFocus();\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/RegionPickerWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.RegionPickerWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n        xmlns:local=\"clr-namespace:Captura\"\n        mc:Ignorable=\"d\"\n        Title=\"Region Picker\"\n        d:DesignHeight=\"600\"\n        d:DesignWidth=\"800\"\n        WindowStyle=\"None\"\n        AllowsTransparency=\"True\"\n        Background=\"Transparent\"\n        Topmost=\"True\"\n        ResizeMode=\"NoResize\"\n        Cursor=\"Cross\"\n        ShowInTaskbar=\"False\">\n    <Window.InputBindings>\n        <KeyBinding Command=\"Close\"\n                    Key=\"Escape\"/>\n    </Window.InputBindings>\n    <Window.CommandBindings>\n        <CommandBinding Command=\"Close\"\n                        Executed=\"CloseClick\"/>\n    </Window.CommandBindings>\n    <Grid MouseMove=\"WindowMouseMove\"\n          MouseLeftButtonDown=\"WindowMouseLeftButtonDown\"\n          MouseLeftButtonUp=\"WindowMouseLeftButtonUp\"\n          Name=\"Grid\">\n        <Grid.Resources>\n            <Style TargetType=\"TextBlock\" BasedOn=\"{StaticResource Title}\"/>\n\n            <SolidColorBrush Color=\"#77000000\" x:Key=\"SurroundColor\"/>\n        </Grid.Resources>\n\n        <xctk:MagnifierManager.Magnifier>\n            <xctk:Magnifier Radius=\"100\"\n                            Style=\"{StaticResource RegionPickerMagnifier}\"\n                            ZoomFactor=\".4\"\n                            BorderThickness=\"1\"\n                            BorderBrush=\"#B7000000\"\n                            Opacity=\"0\">\n                <xctk:Magnifier.RenderTransform>\n                    <TranslateTransform X=\"100\" Y=\"100\"/>\n                </xctk:Magnifier.RenderTransform>\n                <xctk:Magnifier.Triggers>\n                    <EventTrigger RoutedEvent=\"xctk:Magnifier.Loaded\">\n                        <BeginStoryboard>\n                            <Storyboard>\n                                <DoubleAnimation Storyboard.TargetProperty=\"Opacity\"\n                                                 To=\"1\"\n                                                 Duration=\"0:0:0.2\"/>\n                            </Storyboard>\n                        </BeginStoryboard>\n                    </EventTrigger>\n                </xctk:Magnifier.Triggers>\n            </xctk:Magnifier>\n        </xctk:MagnifierManager.Magnifier>\n\n        <Image Name=\"BgImg\"/>\n\n        <local:StripedBorder Visibility=\"Collapsed\"\n                             x:Name=\"Border\"\n                             HorizontalAlignment=\"Left\"\n                             VerticalAlignment=\"Top\"/>\n\n        <local:PuncturedRegion x:Name=\"PunctRegion\"/>\n        \n        <TextBlock Visibility=\"Collapsed\"\n                   Padding=\"5,2\"\n                   FontSize=\"14\"\n                   Name=\"SizeText\"\n                   HorizontalAlignment=\"Left\"\n                   VerticalAlignment=\"Top\"\n                   Foreground=\"White\"\n                   Background=\"#B7000000\"/>\n    </Grid>\n</Window>\n\n"
  },
  {
    "path": "src/Captura/Windows/RegionPickerWindow.xaml.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.IO;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Input;\nusing System.Windows.Media.Imaging;\nusing Captura.Video;\nusing Captura.ViewModels;\nusing MouseEventArgs = System.Windows.Input.MouseEventArgs;\nusing Point = System.Windows.Point;\n\nnamespace Captura\n{\n    public partial class RegionPickerWindow\n    {\n        readonly IWindow[] _windows;\n        readonly IPlatformServices _platformServices;\n\n        Predicate<IWindow> Predicate { get; set; }\n\n        RegionPickerWindow()\n        {\n            InitializeComponent();\n\n            Left = SystemParameters.VirtualScreenLeft;\n            Top = SystemParameters.VirtualScreenTop;\n            Width = SystemParameters.VirtualScreenWidth;\n            Height = SystemParameters.VirtualScreenHeight;\n\n            UpdateBackground();\n\n            _platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            _windows = _platformServices\n                .EnumerateAllWindows()\n                .ToArray();\n        }\n\n        void UpdateBackground()\n        {\n            using var bmp = ScreenShot.Capture();\n            var stream = new MemoryStream();\n            bmp.Save(stream, ImageFormats.Png);\n\n            stream.Seek(0, SeekOrigin.Begin);\n\n            var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default);\n            BgImg.Source = decoder.Frames[0];\n        }\n\n        void CloseClick(object Sender, RoutedEventArgs E)\n        {\n            _start = _end = null;\n\n            Close();\n        }\n\n        void UpdateSizeDisplay(Rect? Rect)\n        {\n            if (Rect == null)\n            {\n                SizeText.Visibility = Visibility.Collapsed;\n            }\n            else\n            {\n                var rect = Rect.Value;\n\n                SizeText.Text = $\"{(int) rect.Width} x {(int) rect.Height}\";\n\n                SizeText.Margin = new Thickness(rect.Left + rect.Width / 2 - SizeText.ActualWidth / 2, rect.Top + rect.Height / 2 - SizeText.ActualHeight / 2, 0, 0);\n\n                SizeText.Visibility = Visibility.Visible;\n            }\n        }\n\n        void WindowMouseMove(object Sender, MouseEventArgs E)\n        {\n            if (_isDragging)\n            {\n                _end = E.GetPosition(Grid);\n\n                var r = GetRegion();\n\n                UpdateSizeDisplay(r);\n\n                if (r == null)\n                {\n                    Unhighlight();\n                    return;\n                }\n\n                HighlightRegion(r.Value);\n            }\n            else\n            {\n                var point = _platformServices.CursorPosition;\n\n                _selectedWindow = _windows\n                        .Where(M => Predicate?.Invoke(M) ?? true)\n                        .FirstOrDefault(M => M.Rectangle.Contains(point));\n\n                if (_selectedWindow == null)\n                {\n                    UpdateSizeDisplay(null);\n\n                    Unhighlight();\n                }\n                else\n                {\n                    var rect = GetSelectedWindowRectangle().Value;\n\n                    UpdateSizeDisplay(rect);\n\n                    HighlightRegion(rect);\n                }\n            }\n        }\n\n        Rect? GetSelectedWindowRectangle()\n        {\n            if (_selectedWindow == null)\n                return null;\n\n            var rect = _selectedWindow.Rectangle;\n\n            return new Rect(-Left + rect.X / Dpi.X,\n                -Top + rect.Y / Dpi.Y,\n                rect.Width / Dpi.X,\n                rect.Height / Dpi.Y);\n        }\n\n        bool _isDragging;\n        Point? _start, _end;\n        IWindow _selectedWindow;\n\n        void WindowMouseLeftButtonDown(object Sender, MouseButtonEventArgs E)\n        {\n            _isDragging = true;\n            _start = E.GetPosition(Grid);\n            _end = null;\n        }\n\n        void WindowMouseLeftButtonUp(object Sender, MouseButtonEventArgs E)\n        {\n            if (!_isDragging)\n                return;\n\n            var current = E.GetPosition(Grid);\n\n            if (current != _start)\n            {\n                _end = E.GetPosition(Grid);\n            }\n            else if (GetSelectedWindowRectangle() is Rect rect)\n            {\n                _start = rect.Location;\n                _end = new Point(rect.Right, rect.Bottom);\n            }\n\n            Close();\n        }\n\n        Rect? GetRegion()\n        {\n            if (_start == null || _end == null)\n            {\n                return null;\n            }\n\n            var end = _end.Value;\n            var start = _start.Value;\n\n            if (end.X < start.X)\n            {\n                var t = start.X;\n                start.X = end.X;\n                end.X = t;\n            }\n\n            if (end.Y < start.Y)\n            {\n                var t = start.Y;\n                start.Y = end.Y;\n                end.Y = t;\n            }\n\n            var width = end.X - start.X;\n            var height = end.Y - start.Y;\n\n            if (width < 0.01 || height < 0.01)\n            {\n                return null;\n            }\n\n            return new Rect(start.X, start.Y, width, height);\n        }\n\n        Rectangle? GetRegionScaled()\n        {\n            var rect = GetRegion();\n\n            if (rect == null)\n            {\n                return null;\n            }\n\n            var r = rect.Value;\n\n            return new Rectangle((int) ((Left + r.X) * Dpi.X),\n                (int)((Top + r.Y) * Dpi.Y),\n                (int)(r.Width * Dpi.X),\n                (int)(r.Height * Dpi.Y));\n        }\n\n        public static Rectangle? PickRegion()\n        {\n            var picker = new RegionPickerWindow();\n\n            picker.ShowDialog();\n\n            return picker.GetRegionScaled();\n        }\n\n        void Unhighlight()\n        {\n            Border.Visibility = Visibility.Collapsed;\n            PunctRegion.Region = null;\n        }\n\n        void HighlightRegion(Rect Region)\n        {\n            var border = RegionSelectorViewModel.BorderSize;\n\n            var regionWithBorder = new Rect(Region.X - border,\n                Region.Y - border,\n                Region.Width + 2 * border,\n                Region.Height + 2 * border);\n\n            Border.Margin = new Thickness(regionWithBorder.X, regionWithBorder.Y, 0, 0);\n            Border.Width = regionWithBorder.Width;\n            Border.Height = regionWithBorder.Height;\n\n            PunctRegion.Region = regionWithBorder;\n\n            Border.Visibility = Visibility.Visible;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/RegionSelector.xaml",
    "content": "﻿<Window x:Class=\"Captura.RegionSelector\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:local=\"clr-namespace:Captura\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\"\n        Title=\"{Binding RegionSelector, Source={StaticResource Loc}, Mode=OneWay}\"\n        Background=\"Transparent\"\n        WindowStyle=\"None\"\n        AllowsTransparency=\"True\"\n        Topmost=\"True\"\n        SizeToContent=\"WidthAndHeight\"\n        Left=\"{Binding RegionSelectorViewModel.LeftDip, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n        Top=\"{Binding RegionSelectorViewModel.TopDip, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n        ShowInTaskbar=\"False\">\n    <Window.Style>\n        <Style TargetType=\"Window\">\n            <Setter Property=\"ResizeMode\" Value=\"CanResize\"/>\n            <Style.Triggers>\n                <DataTrigger Binding=\"{Binding ViewConditions.IsEnabled.Value, Source={StaticResource ServiceLocator}}\" Value=\"False\">\n                    <Setter Property=\"ResizeMode\" Value=\"NoResize\"/>\n                </DataTrigger>\n            </Style.Triggers>\n        </Style>\n    </Window.Style>\n    <Window.InputBindings>\n        <KeyBinding Key=\"Left\"\n                    Command=\"{Binding RegionSelectorViewModel.MoveLeftCommand, Source={StaticResource ServiceLocator}}\"/>\n        <KeyBinding Key=\"Right\"\n                    Command=\"{Binding RegionSelectorViewModel.MoveRightCommand, Source={StaticResource ServiceLocator}}\"/>\n        <KeyBinding Key=\"Up\"\n                    Command=\"{Binding RegionSelectorViewModel.MoveUpCommand, Source={StaticResource ServiceLocator}}\"/>\n        <KeyBinding Key=\"Down\"\n                    Command=\"{Binding RegionSelectorViewModel.MoveDownCommand, Source={StaticResource ServiceLocator}}\"/>\n\n        <KeyBinding Key=\"Left\"\n                    Modifiers=\"Shift\"\n                    Command=\"{Binding RegionSelectorViewModel.DecreaseWidthCommand, Source={StaticResource ServiceLocator}}\"/>\n        <KeyBinding Key=\"Right\"\n                    Modifiers=\"Shift\"\n                    Command=\"{Binding RegionSelectorViewModel.IncreaseWidthCommand, Source={StaticResource ServiceLocator}}\"/>\n        <KeyBinding Key=\"Up\"\n                    Modifiers=\"Shift\"\n                    Command=\"{Binding RegionSelectorViewModel.DecreaseHeightCommand, Source={StaticResource ServiceLocator}}\"/>\n        <KeyBinding Key=\"Down\"\n                    Modifiers=\"Shift\"\n                    Command=\"{Binding RegionSelectorViewModel.IncreaseHeightCommand, Source={StaticResource ServiceLocator}}\"/>\n    </Window.InputBindings>\n    <Grid>\n        <Grid.Resources>\n            <Style TargetType=\"Thumb\">\n                <Setter Property=\"Opacity\" Value=\"0.01\"/>\n                <EventSetter Event=\"DragDelta\" Handler=\"Thumb_OnDragDelta\"/>\n            </Style>\n            <Style x:Key=\"CornerThumb\" TargetType=\"Thumb\" BasedOn=\"{StaticResource {x:Type Thumb}}\">\n                <Setter Property=\"Height\" Value=\"5\"/>\n                <Setter Property=\"Width\" Value=\"5\"/>\n            </Style>\n        </Grid.Resources>\n\n        <Grid Height=\"{Binding RegionSelectorViewModel.HeightDip, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n              Width=\"{Binding RegionSelectorViewModel.WidthDip, Mode=TwoWay, Source={StaticResource ServiceLocator}}\"\n              Name=\"Region\">\n            <local:StripedBorder/>\n\n            <InkCanvas Background=\"Transparent\"\n                       Name=\"InkCanvas\"/>\n        </Grid>\n\n        <Thumb VerticalAlignment=\"Top\"\n               Height=\"2\"\n               Cursor=\"SizeAll\"\n               PreviewMouseLeftButtonDown=\"UIElement_OnPreviewMouseLeftButtonDown\"/>\n\n        <Grid IsEnabled=\"{Binding RecordingViewModel.RecorderState.Value, Source={StaticResource ServiceLocator}, Converter={StaticResource NotRecordingConverter}}\">\n            <Thumb VerticalAlignment=\"Bottom\"\n                   Height=\"2\"\n                   Cursor=\"SizeNS\"\n                   Tag=\"Bottom\"/>\n\n            <Thumb HorizontalAlignment=\"Left\"\n                   Width=\"2\"\n                   Cursor=\"SizeWE\"\n                   Tag=\"Left\"/>\n            \n            <Thumb HorizontalAlignment=\"Right\"\n                   Width=\"2\"\n                   Cursor=\"SizeWE\"\n                   Tag=\"Right\"/>\n\n            <Thumb HorizontalAlignment=\"Left\"\n                   VerticalAlignment=\"Top\"\n                   Style=\"{StaticResource CornerThumb}\"\n                   Cursor=\"SizeNWSE\"\n                   Tag=\"TopLeft\"/>\n\n            <Thumb HorizontalAlignment=\"Right\"\n                   VerticalAlignment=\"Top\"\n                   Style=\"{StaticResource CornerThumb}\"\n                   Cursor=\"SizeNESW\"\n                   Tag=\"TopRight\"/>\n\n            <Thumb HorizontalAlignment=\"Left\"\n                   VerticalAlignment=\"Bottom\"\n                   Style=\"{StaticResource CornerThumb}\"\n                   Cursor=\"SizeNESW\"\n                   Tag=\"BottomLeft\"/>\n\n            <Thumb HorizontalAlignment=\"Right\"\n                   VerticalAlignment=\"Bottom\"\n                   Style=\"{StaticResource CornerThumb}\"\n                   Cursor=\"SizeNWSE\"\n                   Tag=\"BottomRight\"/>\n        </Grid>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/RegionSelector.xaml.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Controls.Primitives;\nusing System.Windows.Input;\nusing System.Windows.Interop;\nusing System.Windows.Media;\nusing Captura.ViewModels;\nusing Color = System.Windows.Media.Color;\nusing Cursors = System.Windows.Input.Cursors;\n\nnamespace Captura\n{\n    public partial class RegionSelector\n    {\n        readonly RegionSelectorViewModel _viewModel;\n\n        public RegionSelector(RegionSelectorViewModel ViewModel)\n        {\n            _viewModel = ViewModel;\n\n            InitializeComponent();\n\n            // Prevent Closing by User\n            Closing += (S, E) => E.Cancel = true;\n\n            ViewModel\n                .BrushColor\n                .Subscribe(M => InkCanvas.DefaultDrawingAttributes.Color = M);\n\n            ViewModel\n                .BrushSize\n                .Subscribe(M => InkCanvas.DefaultDrawingAttributes.Height = InkCanvas.DefaultDrawingAttributes.Width = M);\n\n            ViewModel\n                .SelectedTool\n                .Subscribe(OnToolChange);\n\n            ViewModel\n                .ClearAllDrawingsCommand\n                .Subscribe(() => InkCanvas.Strokes.Clear());\n\n            InkCanvas.DefaultDrawingAttributes.FitToCurve = true;\n        }\n\n        void OnToolChange(InkCanvasEditingMode Tool)\n        {\n            InkCanvas.EditingMode = Tool;\n\n            if (Tool == InkCanvasEditingMode.Ink)\n            {\n                InkCanvas.UseCustomCursor = true;\n                InkCanvas.Cursor = Cursors.Pen;\n            }\n            else InkCanvas.UseCustomCursor = false;\n\n            InkCanvas.Background = new SolidColorBrush(Tool == InkCanvasEditingMode.None\n                ? Colors.Transparent\n                : Color.FromArgb(1, 0, 0, 0));\n        }\n\n        // Prevent Maximizing\n        protected override void OnStateChanged(EventArgs E)\n        {\n            if (WindowState != WindowState.Normal)\n                WindowState = WindowState.Normal;\n\n            base.OnStateChanged(E);\n        }\n\n        protected override void OnRenderSizeChanged(SizeChangedInfo SizeInfo)\n        {\n            InkCanvas.Strokes.Clear();\n\n            base.OnRenderSizeChanged(SizeInfo);\n        }\n\n        public IntPtr Handle => new WindowInteropHelper(this).Handle;\n\n        void UIElement_OnPreviewMouseLeftButtonDown(object Sender, MouseButtonEventArgs E)\n        {\n            DragMove();\n        }\n\n        void Thumb_OnDragDelta(object Sender, DragDeltaEventArgs E)\n        {\n            void DoTop() => _viewModel.ResizeFromTop(E.VerticalChange);\n\n            void DoLeft() => _viewModel.ResizeFromLeft(E.HorizontalChange);\n\n            void DoBottom()\n            {\n                var height = Region.Height + E.VerticalChange;\n\n                if (height > 0)\n                    Region.Height = height;\n            }\n\n            void DoRight()\n            {\n                var width = Region.Width + E.HorizontalChange;\n\n                if (width > 0)\n                    Region.Width = width;\n            }\n\n            if (Sender is FrameworkElement element)\n            {\n                switch (element.Tag)\n                {\n                    case \"Bottom\":\n                        DoBottom();\n                        break;\n\n                    case \"Left\":\n                        DoLeft();\n                        break;\n\n                    case \"Right\":\n                        DoRight();\n                        break;\n\n                    case \"TopLeft\":\n                        DoTop();\n                        DoLeft();\n                        break;\n\n                    case \"TopRight\":\n                        DoTop();\n                        DoRight();\n                        break;\n\n                    case \"BottomLeft\":\n                        DoBottom();\n                        DoLeft();\n                        break;\n\n                    case \"BottomRight\":\n                        DoBottom();\n                        DoRight();\n                        break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/ScreenPickerWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.ScreenPickerWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\"\n        Title=\"Screen Picker\"\n        d:DesignHeight=\"600\"\n        d:DesignWidth=\"800\"\n        ResizeMode=\"NoResize\"\n        SizeToContent=\"WidthAndHeight\"\n        WindowStartupLocation=\"CenterOwner\"\n        ShowInTaskbar=\"False\"\n        Name=\"This\"\n        Background=\"{DynamicResource WindowBackground}\">\n    <Window.InputBindings>\n        <KeyBinding Command=\"Close\"\n                    Key=\"Escape\"/>\n    </Window.InputBindings>\n    <Window.CommandBindings>\n        <CommandBinding Command=\"Close\"\n                        Executed=\"CloseClick\"/>\n    </Window.CommandBindings>\n    <Grid>\n        <ItemsControl ItemsSource=\"{Binding ScreenPickerViewModels, ElementName=This}\"\n                      Margin=\"10\"\n                      Name=\"ScreenContainer\">\n            <ItemsControl.ItemsPanel>\n                <ItemsPanelTemplate>\n                    <Canvas/>\n                </ItemsPanelTemplate>\n            </ItemsControl.ItemsPanel>\n            <ItemsControl.ItemContainerStyle>\n                <Style TargetType=\"ContentPresenter\">\n                    <Setter Property=\"Canvas.Left\" Value=\"{Binding Left}\" />\n                    <Setter Property=\"Canvas.Top\" Value=\"{Binding Top}\" />\n                </Style>\n            </ItemsControl.ItemContainerStyle>\n            <ItemsControl.ItemTemplate>\n                <DataTemplate>\n                    <Border Width=\"{Binding Width}\"\n                            Height=\"{Binding Height}\"\n                            BorderThickness=\"2\"\n                            BorderBrush=\"Chocolate\">\n                        <Button Background=\"{Binding Image}\"\n                                Cursor=\"Hand\"\n                                HorizontalContentAlignment=\"Stretch\"\n                                Padding=\"0\"\n                                Command=\"{Binding SelectScreenCommand, ElementName=This}\"\n                                CommandParameter=\"{Binding Screen}\">\n                            <Label Background=\"#B7000000\"\n                                   Foreground=\"White\"\n                                   Content=\"{Binding Screen.DeviceName}\"\n                                   HorizontalContentAlignment=\"Center\"\n                                   Margin=\"0,0,0,10\"/>\n                        </Button>\n                    </Border>\n                </DataTemplate>\n            </ItemsControl.ItemTemplate>\n        </ItemsControl>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/ScreenPickerWindow.xaml.cs",
    "content": "﻿using System.Collections.ObjectModel;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Input;\nusing Captura.Video;\nusing Captura.ViewModels;\nusing Reactive.Bindings;\n\nnamespace Captura\n{\n    public partial class ScreenPickerWindow\n    {\n        const double Scale = 0.15;\n\n        public ObservableCollection<ScreenPickerViewModel> ScreenPickerViewModels { get; } = new ObservableCollection<ScreenPickerViewModel>();\n\n        public ICommand SelectScreenCommand { get; }\n\n        ScreenPickerWindow()\n        {\n            SelectScreenCommand = new ReactiveCommand<IScreen>()\n                .WithSubscribe(M =>\n                {\n                    SelectedScreen = M;\n\n                    Close();\n                });\n\n            InitializeComponent();\n\n            ScreenContainer.Width = SystemParameters.VirtualScreenWidth * Scale;\n            ScreenContainer.Height = SystemParameters.VirtualScreenHeight * Scale;\n\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            var screens = platformServices.EnumerateScreens().ToArray();\n\n            foreach (var screen in screens)\n            {\n                ScreenPickerViewModels.Add(new ScreenPickerViewModel(screen, Scale));\n            }\n        }\n\n        public IScreen SelectedScreen { get; private set; }\n\n        void CloseClick(object Sender, RoutedEventArgs E)\n        {\n            SelectedScreen = null;\n\n            Close();\n        }\n\n        public static IScreen PickScreen()\n        {\n            var picker = new ScreenPickerWindow\n            {\n                Owner = MainWindow.Instance\n            };\n\n            picker.ShowDialog();\n\n            return picker.SelectedScreen;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/SettingsWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.SettingsWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:mui=\"http://firstfloorsoftware.com/ModernUI\"\n        Title=\"{Binding Configure, Source={StaticResource Loc}, Mode=OneWay}\"\n        Height=\"550\"\n        Width=\"750\"\n        Background=\"{DynamicResource WindowBackground}\">\n    <DockPanel>\n        <DockPanel DockPanel.Dock=\"Top\"\n                   Margin=\"5,10,0,0\">\n            <mui:ModernButton IconData=\"{Binding Icons.Back, Source={StaticResource ServiceLocator}}\"\n                              IsEnabled=\"{Binding CanGoBack, ElementName=NavFrame}\"\n                              EllipseDiameter=\"40\"\n                              IconWidth=\"35\"\n                              IconHeight=\"25\"\n                              Margin=\"5,0,2,0\"\n                              Click=\"OnGoBack\"/>\n\n            <mui:ModernButton IconData=\"{Binding Icons.Forward, Source={StaticResource ServiceLocator}}\"\n                              IsEnabled=\"{Binding CanGoForward, ElementName=NavFrame}\"\n                              Click=\"OnGoNext\"/>\n\n            <Label>\n                <TextBlock Text=\"{Binding Content.Title, ElementName=NavFrame}\"\n                           Style=\"{StaticResource Title}\"\n                           Margin=\"10,0,0,0\"/>\n            </Label>\n        </DockPanel>\n\n        <GridSplitter DockPanel.Dock=\"Top\"\n                      Height=\"1\"\n                      Margin=\"0,10\"\n                      IsEnabled=\"False\"/>\n\n        <Frame Source=\"../Pages/SettingsPage.xaml\"\n               NavigationUIVisibility=\"Hidden\"\n               Name=\"NavFrame\"\n               Padding=\"5,0\"\n               Navigated=\"NavFrame_OnNavigated\">\n            <Frame.CommandBindings>\n                <CommandBinding Command=\"GoToPage\"\n                                Executed=\"OnGoToPage\"/>\n            </Frame.CommandBindings>\n        </Frame>\n    </DockPanel>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/SettingsWindow.xaml.cs",
    "content": "﻿using System;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Animation;\nusing System.Windows.Navigation;\n\nnamespace Captura\n{\n    public partial class SettingsWindow\n    {\n        SettingsWindow()\n        {\n            InitializeComponent();\n        }\n\n        static SettingsWindow _instance;\n\n        public static void ShowInstance()\n        {\n            if (_instance == null)\n            {\n                _instance = new SettingsWindow();\n\n                _instance.Closed += (S, E) => _instance = null;\n            }\n\n            _instance.ShowAndFocus();\n        }\n\n        void OnGoToPage(object Sender, ExecutedRoutedEventArgs E)\n        {\n            if (Sender is Frame frame)\n            {\n                switch (E.Parameter)\n                {\n                    case string s:\n                        frame.Navigate(new Uri(s, UriKind.RelativeOrAbsolute));\n                        break;\n\n                    case { } o:\n                        frame.Navigate(o);\n                        break;\n                }\n            }\n        }\n\n        static void ShowPage(string PageName)\n        {\n            ShowInstance();\n\n            _instance.NavFrame.Navigate(new Uri($\"/Pages/{PageName}Page.xaml\", UriKind.RelativeOrAbsolute));\n        }\n\n        public static void ShowFFmpegLogs() => ShowPage(\"FFmpegLogs\");\n\n        public static void ShowWebcamPage()\n        {\n            ShowInstance();\n\n            _instance.NavFrame.Navigate(ServiceProvider.Get<WebcamPage>());\n        }\n\n        void OnGoBack(object Sender, RoutedEventArgs E)\n        {\n            NavFrame.GoBack();\n        }\n\n        void OnGoNext(object Sender, RoutedEventArgs E)\n        {\n            NavFrame.GoForward();\n        }\n\n        void NavFrame_OnNavigated(object Sender, NavigationEventArgs E)\n        {\n            if (E.Content is Page page)\n            {\n                var transform = new TranslateTransform();\n\n                page.RenderTransform = transform;\n\n                var anim = new DoubleAnimation\n                {\n                    Duration = TimeSpan.FromSeconds(0.3),\n                    DecelerationRatio = 0.5,\n                    From = 100,\n                    To = 0\n                };\n\n                transform.BeginAnimation(TranslateTransform.XProperty, anim);\n            }\n            else Console.WriteLine(E.Content);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/TrimmerWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.Views.TrimmerWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:xctk=\"http://schemas.xceed.com/wpf/xaml/toolkit\"\n        xmlns:captura=\"clr-namespace:Captura\"\n        mc:Ignorable=\"d\"\n        Title=\"Trim\"\n        Height=\"600\"\n        Width=\"600\">\n    <Window.DataContext>\n        <captura:TrimmerViewModel/>\n    </Window.DataContext>\n    <Window.InputBindings>\n        <KeyBinding Command=\"{Binding OpenCommand}\"\n                    Key=\"O\"\n                    Modifiers=\"Control\"/>\n    </Window.InputBindings>\n    <DockPanel Background=\"{DynamicResource WindowBackground}\">\n        <DockPanel LastChildFill=\"False\"\n                   DockPanel.Dock=\"Bottom\"\n                   Margin=\"5\">\n            <Label Content=\"{Binding From, Converter={StaticResource IntegralTimeSpanConverter}}\"/>\n            <Label DockPanel.Dock=\"Right\"\n                   Content=\"{Binding To, Converter={StaticResource IntegralTimeSpanConverter}}\"/>\n        </DockPanel>\n\n        <xctk:RangeSlider Maximum=\"{Binding End, Converter={StaticResource TimeSpanToSecondsConverter}}\"\n                          LowerValue=\"{Binding From, Converter={StaticResource TimeSpanToSecondsConverter}}\"\n                          HigherValue=\"{Binding To, Converter={StaticResource TimeSpanToSecondsConverter}}\"\n                          Background=\"LightGray\"\n                          LowerRangeBackground=\"LightGray\"\n                          HigherRangeBackground=\"LightGray\"\n                          RangeBackground=\"#77FFC7\"\n                          DockPanel.Dock=\"Bottom\"\n                          Margin=\"10,20\"/>\n\n        <DockPanel DockPanel.Dock=\"Bottom\"\n                   Margin=\"10,20\">\n            <captura:ModernButton Margin=\"5,0\"\n                                  Command=\"{Binding PlayCommand}\"\n                                  Style=\"{Binding IsPlaying, Converter={StaticResource IsPlayingToButtonStyleConverter}}\"/>\n\n            <Label Content=\"{Binding PlaybackPosition, Converter={StaticResource IntegralTimeSpanConverter}}\"\n                   Margin=\"5,0\"\n                   DockPanel.Dock=\"Right\"/>\n\n            <Slider Visibility=\"{Binding IsPlaying, Converter={StaticResource BoolToVisibilityConverter}}\"\n                    Value=\"{Binding PlaybackPosition, Converter={StaticResource TimeSpanToSecondsConverter}, Mode=OneWay}\"\n                    SelectionEnd=\"{Binding To, Converter={StaticResource TimeSpanToSecondsConverter}, Mode=OneWay}\"\n                    Maximum=\"{Binding End, Converter={StaticResource TimeSpanToSecondsConverter}}\"\n                    SelectionStart=\"{Binding From, Converter={StaticResource TimeSpanToSecondsConverter}}\"\n                    IsSelectionRangeEnabled=\"True\"\n                    Style=\"{StaticResource RoundSlider}\"\n                    IsMoveToPointEnabled=\"True\"\n                    IsManipulationEnabled=\"True\" \n                    IsTabStop=\"False\"\n                    PreviewMouseLeftButtonUp=\"Slider_PreviewMouseLeftButtonUp\" \n                    PreviewMouseLeftButtonDown=\"Slider_PreviewMouseLeftButtonDown\"\n                    MouseLeftButtonUp=\"Slider_MouseLeftButtonUp\"/>\n        </DockPanel>\n\n        <Label DockPanel.Dock=\"Top\"\n               Margin=\"5\">\n            <TextBlock Text=\"{Binding FileName, TargetNullValue='No File Loaded'}\"\n                       Style=\"{StaticResource Title}\"/>\n        </Label>\n\n        <Label DockPanel.Dock=\"Top\"\n               Margin=\"5\"\n               Content=\"{Binding End, Converter={StaticResource IntegralTimeSpanConverter}}\"/>\n\n        <Grid DockPanel.Dock=\"Top\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition/>\n                <ColumnDefinition/>\n            </Grid.ColumnDefinitions>\n\n            <Button Margin=\"5\"\n                    Command=\"{Binding OpenCommand}\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.OpenFile, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"Open File ...\"/>\n                </DockPanel>\n            </Button>\n\n            <Button Margin=\"5\"\n                    Grid.Column=\"1\"\n                    Command=\"{Binding TrimCommand}\">\n                <DockPanel>\n                    <Path Data=\"{Binding Icons.Trim, Source={StaticResource ServiceLocator}}\"\n                          Width=\"15\"\n                          Height=\"15\"\n                          Margin=\"0,0,10,0\"\n                          Stretch=\"Uniform\"\n                          HorizontalAlignment=\"Center\"\n                          VerticalAlignment=\"Center\"/>\n\n                    <TextBlock Text=\"Trim ...\"/>\n                </DockPanel>\n            </Button>\n        </Grid>\n\n        <MediaElement Name=\"MediaElement\"\n                      LoadedBehavior=\"Manual\"\n                      UnloadedBehavior=\"Manual\"\n                      ScrubbingEnabled=\"True\"\n                      Margin=\"0,10,0,0\"/>\n    </DockPanel>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/TrimmerWindow.xaml.cs",
    "content": "﻿using System;\nusing System.Windows.Controls;\nusing System.Windows.Input;\n\nnamespace Captura.Views\n{\n    public partial class TrimmerWindow\n    {\n        public TrimmerWindow()\n        {\n            InitializeComponent();\n            \n            if (DataContext is TrimmerViewModel vm)\n            {\n                vm.AssignPlayer(MediaElement);\n\n                Closing += (S, E) => vm.Dispose();\n            }\n        }\n\n        public void Open(string FileName)\n        {\n            if (DataContext is TrimmerViewModel vm)\n            {\n                vm.Open(FileName);\n            }\n        }\n\n        void Slider_PreviewMouseLeftButtonUp(object Sender, MouseButtonEventArgs E)\n        {\n            if (DataContext is TrimmerViewModel vm && Sender is Slider slider)\n            {\n                if (!vm.IsDragging)\n                    return;\n\n                vm.PlaybackPosition = TimeSpan.FromSeconds(slider.Value);\n\n                vm.IsDragging = false;\n            }\n        }\n\n        void Slider_PreviewMouseLeftButtonDown(object Sender, MouseButtonEventArgs E)\n        {\n            if (DataContext is TrimmerViewModel vm)\n            {\n                vm.IsDragging = true;\n            }\n        }\n\n        void Slider_MouseLeftButtonUp(object Sender, MouseButtonEventArgs E)\n        {\n            if (DataContext is TrimmerViewModel vm && Sender is Slider slider)\n            {\n                vm.PlaybackPosition = TimeSpan.FromSeconds(slider.Value);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/VideoSourcePickerWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.VideoSourcePickerWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\"\n        Title=\"Source Picker\"\n        d:DesignHeight=\"600\"\n        d:DesignWidth=\"800\"\n        WindowStyle=\"None\"\n        AllowsTransparency=\"True\"\n        Topmost=\"True\"\n        ResizeMode=\"NoResize\"\n        ShowInTaskbar=\"False\">\n    <Window.InputBindings>\n        <KeyBinding Command=\"Close\"\n                    Key=\"Escape\"/>\n    </Window.InputBindings>\n    <Window.CommandBindings>\n        <CommandBinding Command=\"Close\"\n                        Executed=\"CloseClick\"/>\n    </Window.CommandBindings>\n    <Grid MouseMove=\"WindowMouseMove\"\n          MouseLeftButtonDown=\"WindowMouseLeftButtonDown\"\n          Name=\"Grid\"\n          Background=\"Transparent\">\n        <Grid.Resources>\n            <Style TargetType=\"TextBlock\" BasedOn=\"{StaticResource Title}\"/>\n        </Grid.Resources>\n        \n        <Border Opacity=\"0\"\n                Background=\"#57FFFFFF\"\n                BorderBrush = \"#333333\"\n                Name=\"Border\"\n                HorizontalAlignment=\"Left\"\n                VerticalAlignment=\"Top\"/>\n\n        <Grid.Triggers>\n            <EventTrigger RoutedEvent=\"Grid.Loaded\">\n                <BeginStoryboard>\n                    <Storyboard>\n                        <ColorAnimation Storyboard.TargetProperty=\"Background.Color\"\n                                        To=\"#57FFFFFF\"\n                                        Duration=\"0:0:0.15\"/>\n                    </Storyboard>\n                </BeginStoryboard>\n            </EventTrigger>\n        </Grid.Triggers>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/VideoSourcePickerWindow.xaml.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.IO;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Animation;\nusing System.Windows.Media.Imaging;\nusing Captura.Video;\nusing Color = System.Windows.Media.Color;\nusing Cursors = System.Windows.Input.Cursors;\nusing HorizontalAlignment = System.Windows.HorizontalAlignment;\nusing MouseEventArgs = System.Windows.Input.MouseEventArgs;\n\nnamespace Captura\n{\n    public partial class VideoSourcePickerWindow\n    {\n        enum VideoPickerMode\n        {\n            Window,\n            Screen\n        }\n\n        readonly VideoPickerMode _mode;\n\n        Predicate<IWindow> Predicate { get; set; }\n\n        VideoSourcePickerWindow(VideoPickerMode Mode)\n        {\n            _mode = Mode;\n            InitializeComponent();\n\n            Left = SystemParameters.VirtualScreenLeft;\n            Top = SystemParameters.VirtualScreenTop;\n            Width = SystemParameters.VirtualScreenWidth;\n            Height = SystemParameters.VirtualScreenHeight;\n\n            UpdateBackground();\n\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            _screens = platformServices.EnumerateScreens().ToArray();\n            _windows = platformServices.EnumerateWindows().ToArray();\n\n            ShowCancelText();\n        }\n\n        readonly IScreen[] _screens;\n\n        readonly IWindow[] _windows;\n\n        public IScreen SelectedScreen { get; private set; }\n\n        public IWindow SelectedWindow { get; private set; }\n\n        void UpdateBackground()\n        {\n            using var bmp = ScreenShot.Capture();\n            var stream = new MemoryStream();\n            bmp.Save(stream, ImageFormats.Png);\n\n            stream.Seek(0, SeekOrigin.Begin);\n\n            var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default);\n            Background = new ImageBrush(decoder.Frames[0]);\n        }\n\n        void BeginClose()\n        {\n            var duration = new Duration(TimeSpan.FromMilliseconds(200));\n\n            var opacityAnim = new DoubleAnimation(0, duration);\n\n            opacityAnim.Completed += (S, E) => Close();\n\n            BeginAnimation(OpacityProperty, opacityAnim);\n        }\n\n        void ShowCancelText()\n        {\n            foreach (var screen in _screens)\n            {\n                var bounds = screen.Rectangle;\n\n                var left = -Left + bounds.Left / Dpi.X;\n                var top = -Top + bounds.Top / Dpi.Y;\n                var width = bounds.Width / Dpi.X;\n                var height = bounds.Height / Dpi.Y;\n\n                var container = new ContentControl\n                {\n                    Width = width,\n                    Height = height,\n                    Margin = new Thickness(left, top, 0, 0),\n                    VerticalAlignment = VerticalAlignment.Top,\n                    HorizontalAlignment = HorizontalAlignment.Left\n                };\n\n                var textBlock = new TextBlock\n                {\n                    Text = $\"Select {_mode} or Press Esc to Cancel\",\n                    HorizontalAlignment = HorizontalAlignment.Center,\n                    VerticalAlignment = VerticalAlignment.Center,\n                    Padding = new Thickness(10, 5, 10, 5),\n                    Foreground = new SolidColorBrush(Colors.White),\n                    Background = new SolidColorBrush(Color.FromArgb(183, 0, 0, 0))\n                };\n\n                container.Content = textBlock;\n\n                Grid.Children.Add(container);\n            }\n        }\n\n        void CloseClick(object Sender, RoutedEventArgs E)\n        {\n            SelectedScreen = null;\n            SelectedWindow = null;\n\n            BeginClose();\n        }\n\n        Rectangle? _lastRectangle;\n\n        void UpdateBorderAndCursor(Rectangle? Rect)\n        {\n            if (_lastRectangle == Rect)\n                return;\n\n            _lastRectangle = Rect;\n\n            var storyboard = new Storyboard();\n\n            var duration = new Duration(TimeSpan.FromMilliseconds(100));\n\n            if (Rect == null)\n            {\n                Cursor = Cursors.Arrow;\n\n                var opacityAnim = new DoubleAnimation(0, duration);\n                Storyboard.SetTargetProperty(opacityAnim, new PropertyPath(nameof(Opacity)));\n                storyboard.Children.Add(opacityAnim);\n            }\n            else\n            {\n                Cursor = Cursors.Hand;\n\n                var opacityAnim = new DoubleAnimation(1, duration);\n                Storyboard.SetTargetProperty(opacityAnim, new PropertyPath(nameof(Opacity)));\n                storyboard.Children.Add(opacityAnim);\n\n                var rect = Rect.Value;\n\n                var margin = new Thickness(-Left + rect.Left / Dpi.X, -Top + rect.Top / Dpi.Y, 0, 0);\n                var marginAnim = new ThicknessAnimation(margin, duration);\n                Storyboard.SetTargetProperty(marginAnim, new PropertyPath(nameof(Margin)));\n                storyboard.Children.Add(marginAnim);\n\n                var widthAnim = new DoubleAnimation(Border.ActualWidth, rect.Width / Dpi.X, duration);\n                Storyboard.SetTargetProperty(widthAnim, new PropertyPath(nameof(Width)));\n                storyboard.Children.Add(widthAnim);\n\n                var heightAnim = new DoubleAnimation(Border.ActualHeight, rect.Height / Dpi.Y, duration);\n                Storyboard.SetTargetProperty(heightAnim, new PropertyPath(nameof(Height)));\n                storyboard.Children.Add(heightAnim);\n            }\n\n            Border.BeginStoryboard(storyboard);\n        }\n\n        void WindowMouseMove(object Sender, MouseEventArgs E)\n        {\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            var point = platformServices.CursorPosition;\n\n            switch (_mode)\n            {\n                case VideoPickerMode.Screen:\n                    SelectedScreen = _screens.FirstOrDefault(M => M.Rectangle.Contains(point));\n\n                    UpdateBorderAndCursor(SelectedScreen?.Rectangle);\n                    break;\n\n                case VideoPickerMode.Window:\n                    SelectedWindow = _windows\n                        .Where(M => Predicate?.Invoke(M) ?? true)\n                        .FirstOrDefault(M => M.Rectangle.Contains(point));\n                    \n                    UpdateBorderAndCursor(SelectedWindow?.Rectangle);\n                    break;\n            }\n        }\n\n        void WindowMouseLeftButtonDown(object Sender, MouseButtonEventArgs E)\n        {\n            switch (_mode)\n            {\n                case VideoPickerMode.Screen when SelectedScreen != null:\n                case VideoPickerMode.Window when SelectedWindow != null:\n                    BeginClose();\n                    break;\n            }\n        }\n\n        public static IScreen PickScreen()\n        {\n            var picker = new VideoSourcePickerWindow(VideoPickerMode.Screen);\n\n            picker.ShowDialog();\n\n            return picker.SelectedScreen;\n        }\n\n        public static IWindow PickWindow(Predicate<IWindow> Filter)\n        {\n            var picker = new VideoSourcePickerWindow(VideoPickerMode.Window)\n            {\n                Border =\n                {\n                    BorderThickness = new Thickness(5)\n                },\n                Predicate = Filter\n            };\n\n            picker.ShowDialog();\n\n            return picker.SelectedWindow;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/Windows/YouTubeUploaderWindow.xaml",
    "content": "﻿<Window x:Class=\"Captura.YouTubeUploaderWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:captura=\"clr-namespace:Captura\"\n        Title=\"YouTube Uploader\"\n        Height=\"400\"\n        Width=\"450\"\n        Background=\"{DynamicResource WindowBackground}\"\n        DataContext=\"{Binding YouTubeUploaderViewModel, Source={StaticResource ServiceLocator}}\">\n    <Grid>\n        <DockPanel Margin=\"10\">\n            <StackPanel Orientation=\"Horizontal\"\n                        DockPanel.Dock=\"Bottom\"\n                        HorizontalAlignment=\"Right\"\n                        Margin=\"0,5\">\n                <Button Content=\"{Binding UploadBtnText}\"\n                        Margin=\"0,0,5,0\"\n                        Command=\"{Binding UploadCommand}\"/>\n\n                <Button Content=\"{Binding CancelBtnText}\"\n                        Click=\"Cancel_Click\"/>\n            </StackPanel>\n\n            <Label ContentStringFormat=\"{}File: {0}\"\n                   Content=\"{Binding FileName}\"\n                   FontWeight=\"DemiBold\"\n                   Margin=\"0,0,0,5\"\n                   DockPanel.Dock=\"Top\"/>\n\n            <Label Content=\"Title\"\n                   Margin=\"0,0,0,2\"\n                   DockPanel.Dock=\"Top\"/>\n\n            <TextBox DockPanel.Dock=\"Top\"\n                     Text=\"{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"\n                     IsReadOnly=\"{Binding BeganUploading}\"/>\n\n            <Label Content=\"Description\"\n                   Margin=\"0,7,0,2\"\n                   DockPanel.Dock=\"Top\"/>\n\n            <DockPanel Visibility=\"{Binding Link, Converter={StaticResource NotNullConverter}}\"\n                       DockPanel.Dock=\"Bottom\">\n                <Path Data=\"{Binding Icons.Link, Source={StaticResource ServiceLocator}}\"\n                      Width=\"15\"\n                      Height=\"15\"\n                      Margin=\"0,0,7,0\"\n                      Stretch=\"Uniform\"\n                      HorizontalAlignment=\"Center\"\n                      VerticalAlignment=\"Center\"/>\n\n                <captura:ModernButton IconData=\"{Binding Icons.Clipboard, Source={StaticResource ServiceLocator}}\"\n                                      Command=\"{Binding CopyLinkCommand}\"\n                                      DockPanel.Dock=\"Right\"/>\n\n                <TextBlock VerticalAlignment=\"Center\">\n                    <Hyperlink Command=\"{Binding OpenVideoCommand}\"\n                               NavigateUri=\"{Binding Link, Mode=OneWay}\"\n                               Foreground=\"LimeGreen\">\n                        <Run Text=\"{Binding Link, Mode=OneWay}\"/>\n                    </Hyperlink>\n                </TextBlock>\n            </DockPanel>\n\n            <ProgressBar DockPanel.Dock=\"Bottom\"\n                         Value=\"{Binding Progress, Mode=OneWay}\"\n                         Margin=\"0,2\"\n                         Height=\"1\"/>\n\n            <ListView ItemsSource=\"{Binding PrivacyStatuses}\"\n                      SelectedValue=\"{Binding PrivacyStatus}\"\n                      Margin=\"0,10\"\n                      SelectionMode=\"Single\"\n                      BorderThickness=\"0.4\"\n                      HorizontalContentAlignment=\"Center\"\n                      DockPanel.Dock=\"Bottom\"\n                      IsEnabled=\"{Binding BeganUploading, Converter={StaticResource NegatingConverter}}\">\n                <ListView.ItemsPanel>\n                    <ItemsPanelTemplate>\n                        <UniformGrid Rows=\"1\"/>\n                    </ItemsPanelTemplate>\n                </ListView.ItemsPanel>\n                <ListView.ItemTemplate>\n                    <DataTemplate>\n                        <Grid Background=\"#01000000\">\n                            <TextBlock Text=\"{Binding}\"\n                                       HorizontalAlignment=\"Center\"/>\n                        </Grid>\n                    </DataTemplate>\n                </ListView.ItemTemplate>\n            </ListView>\n\n            <TextBox Text=\"{Binding Description, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"\n                     AcceptsReturn=\"True\"\n                     VerticalScrollBarVisibility=\"Auto\"\n                     IsReadOnly=\"{Binding BeganUploading}\"/>\n        </DockPanel>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "src/Captura/Windows/YouTubeUploaderWindow.xaml.cs",
    "content": "﻿using System.Windows;\nusing Captura.ViewModels;\n\nnamespace Captura\n{\n    public partial class YouTubeUploaderWindow\n    {\n        public YouTubeUploaderWindow()\n        {\n            InitializeComponent();\n\n            Closing += async (S, E) =>\n            {\n                if (DataContext is YouTubeUploaderViewModel vm)\n                {\n                    if (!await vm.Cancel())\n                    {\n                        E.Cancel = true;\n                    }\n                }\n            };\n        }\n\n        public async void Open(string FileName)\n        {\n            if (DataContext is YouTubeUploaderViewModel vm)\n            {\n                await vm.Init(FileName);\n            }\n        }\n\n        void Cancel_Click(object Sender, RoutedEventArgs E)\n        {\n            Close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura/app.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <startup>\n    <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.7.2\"/>\n  </startup>\n  <runtime>\n    <assemblyBinding xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n      <probing privatePath=\"lib\"/>\n    </assemblyBinding>\n  </runtime>\n</configuration>\n"
  },
  {
    "path": "src/Captura.Audio/Captura.Audio.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Captura.Audio/IAudioFileWriter.cs",
    "content": "﻿using System;\n\nnamespace Captura.Audio\n{\n    /// <summary>\n    /// Encodes Audio into an audio file.\n    /// </summary>\n    public interface IAudioFileWriter : IDisposable\n    {\n        /// <summary>\n        /// Writes to file.\n        /// </summary>\n        void Write(byte[] Data, int Offset, int Count);\n\n        /// <summary>\n        /// Writes all buffered data to file.\n        /// </summary>\n        void Flush();\n    }\n}\n"
  },
  {
    "path": "src/Captura.Audio/IAudioItem.cs",
    "content": "﻿using System;\n\nnamespace Captura.Audio\n{\n    public interface IAudioItem : IDisposable\n    {\n        string Name { get; }\n\n        bool IsLoopback { get; }\n\n        void StartListeningForPeakLevel();\n\n        void StopListeningForPeakLevel();\n\n        double PeakLevel { get; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Audio/IAudioProvider.cs",
    "content": "﻿using System;\n\nnamespace Captura.Audio\n{\n    /// <summary>\n    /// Provides Recorded Audio.\n    /// </summary>\n    public interface IAudioProvider : IDisposable\n    {\n        /// <summary>\n        /// Gets the Recording WaveFormat.\n        /// </summary>\n        WaveFormat WaveFormat { get; }\n\n        /// <summary>\n        /// Start Recording.\n        /// </summary>\n        void Start();\n\n        /// <summary>\n        /// Stop Recording.\n        /// </summary>\n        void Stop();\n\n        /// <summary>\n        /// Read data into a buffer.\n        /// </summary>\n        /// <param name=\"Buffer\">Buffer to read data into.</param>\n        /// <param name=\"Offset\">Offset from which data should be written to the buffer.</param>\n        /// <param name=\"Length\">Number of bytes to write to the buffer.</param>\n        /// <returns>Number of bytes read.</returns>\n        int Read(byte[] Buffer, int Offset, int Length);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Audio/IAudioSource.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Captura.Audio\n{\n    public interface IAudioSource : IDisposable\n    {\n        string Name { get; }\n\n        IEnumerable<IAudioItem> Microphones { get; }\n\n        IAudioItem DefaultMicrophone { get; }\n\n        IEnumerable<IAudioItem> Speakers { get; }\n\n        IAudioItem DefaultSpeaker { get; }\n\n        IAudioProvider GetAudioProvider(IAudioItem Microphone, IAudioItem Speaker);\n\n        event Action DevicesUpdated;\n    }\n}"
  },
  {
    "path": "src/Captura.Audio/IAudioWriterItem.cs",
    "content": "﻿namespace Captura.Audio\n{\n    public interface IAudioWriterItem\n    {\n        string Name { get; }\n\n        string Extension { get; }\n\n        IAudioFileWriter GetAudioFileWriter(string FileName, WaveFormat Wf, int AudioQuality);\n    }\n}"
  },
  {
    "path": "src/Captura.Audio/WaveFormat/WaveFormat.cs",
    "content": "using System;\nusing System.IO;\n\nnamespace Captura.Audio\n{\n    /// <summary>\n    /// Represents a Wave file format\n    /// </summary>\n    public class WaveFormat\n    {\n        /// <summary>\n        /// Creates a new PCM 44.1Khz stereo 16 bit format\n        /// </summary>\n        public WaveFormat() : this(44100, 16, 2) { }\n\n        /// <summary>\n        /// Creates a new 16 bit wave format with the specified sample\n        /// rate and channel count\n        /// </summary>\n        /// <param name=\"SampleRate\">Sample Rate</param>\n        /// <param name=\"Channels\">Number of channels</param>\n        public WaveFormat(int SampleRate, int Channels) : this(SampleRate, 16, Channels) { }\n\n        /// <summary>\n        /// Creates a new PCM format with the specified sample rate, bit depth and channels\n        /// </summary>\n        public WaveFormat(int SampleRate, int BitsPerSample, int Channels)\n        {\n            if (Channels < 1)\n                throw new ArgumentOutOfRangeException(nameof(Channels), \"Channels must be 1 or greater\");\n\n            // minimum 16 bytes, sometimes 18 for PCM\n            Encoding = WaveFormatEncoding.Pcm;\n            this.Channels = (short)Channels;\n            this.SampleRate = SampleRate;\n            this.BitsPerSample = (short)BitsPerSample;\n            ExtraSize = 0;\n\n            BlockAlign = (short)(Channels * (BitsPerSample / 8));\n            AverageBytesPerSecond = this.SampleRate * BlockAlign;\n        }\n\n        /// <summary>\n        /// Creates a new 32 bit IEEE floating point wave format\n        /// </summary>\n        /// <param name=\"SampleRate\">sample rate</param>\n        /// <param name=\"Channels\">number of channels</param>\n        public static WaveFormat CreateIeeeFloatWaveFormat(int SampleRate, int Channels)\n        {\n            return new WaveFormat\n            {\n                Encoding = WaveFormatEncoding.Float,\n                Channels = (short)Channels,\n                BitsPerSample = 32,\n                SampleRate = SampleRate,\n                BlockAlign = (short)(4 * Channels),\n                AverageBytesPerSecond = SampleRate * 4 * Channels,\n                ExtraSize = 0\n            };\n        }\n        \n        /// <summary>\n        /// Returns the encoding type used\n        /// </summary>\n        public WaveFormatEncoding Encoding { get; set; }\n\n        /// <summary>\n        /// Writes this WaveFormat object to a stream\n        /// </summary>\n        /// <param name=\"Writer\">the output stream</param>\n        public virtual void Serialize(BinaryWriter Writer)\n        {\n            Writer.Write((short)Encoding);\n            Writer.Write((short)Channels);\n            Writer.Write(SampleRate);\n            Writer.Write(AverageBytesPerSecond);\n            Writer.Write((short)BlockAlign);\n            Writer.Write((short)BitsPerSample);\n            Writer.Write((short)ExtraSize);\n        }\n\n        /// <summary>\n        /// Returns the number of channels (1=mono,2=stereo etc)\n        /// </summary>\n        public int Channels { get; set; }\n\n        /// <summary>\n        /// Returns the sample rate (samples per second)\n        /// </summary>\n        public int SampleRate { get; set; }\n\n        /// <summary>\n        /// Returns the average number of bytes used per second\n        /// </summary>\n        public int AverageBytesPerSecond { get; set; }\n\n        /// <summary>\n        /// Returns the block alignment\n        /// </summary>\n        public int BlockAlign { get; set; }\n\n        /// <summary>\n        /// Returns the number of bits per sample (usually 16 or 32, sometimes 24 or 8)\n        /// Can be 0 for some codecs\n        /// </summary>\n        public int BitsPerSample { get; set; }\n\n        /// <summary>\n        /// Returns the number of extra bytes used by this waveformat.\n        /// Often 0, except for compressed formats which store extra data after the WAVEFORMATEX header\n        /// </summary>\n        public int ExtraSize { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Audio/WaveFormat/WaveFormatEncoding.cs",
    "content": "namespace Captura.Audio\n{\n    /// <summary>\n    /// WaveFormat Encoding\n    /// </summary>\n    public enum WaveFormatEncoding : ushort\n    {\n        /// <summary>\n        /// Unknown.\n        /// </summary>\n        Unknown = 0x0000,\n\n        /// <summary>\n        /// Pulse Code Modulation.\n        /// </summary>\n        Pcm = 0x0001,\n\n        /// <summary>\n        /// IEEE Float.\n        /// </summary>\n        Float = 0x0003,\n\n        /// <summary>\n        /// MPEG Layer 3 (MP3).\n        /// </summary>\n        Mp3 = 0x0055,\n\n        /// <summary>\n        /// Wave Format Extensible.\n        /// </summary>\n        Extensible = 0xFFFE\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Captura.Base.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageReference Include=\"System.Drawing.Common\" Version=\"4.5.0\" />\n    <PackageReference Include=\"Ninject\" Version=\"3.3.4\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Audio\\Captura.Audio.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Captura.Base/ComparableExtensions.cs",
    "content": "﻿using System;\n\nnamespace Captura\n{\n    public static class ComparableExtensions\n    {\n        public static T Clip<T>(this T Value, T Minimum, T Maximum) where T : IComparable<T>\n        {\n            if (Value.CompareTo(Minimum) < 0)\n                return Minimum;\n\n            if (Value.CompareTo(Maximum) > 0)\n                return Maximum;\n\n            return Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/DelegateCommand.cs",
    "content": "﻿using System;\nusing System.Windows.Input;\nusing Captura.Models;\n\nnamespace Captura\n{\n    public class DelegateCommand : ICommand\n    {\n        readonly Action<object> _execute;\n        bool _canExecute;\n        readonly SyncContextManager _syncContext = new SyncContextManager();\n        \n        public DelegateCommand(Action<object> OnExecute, bool CanExecute = true)\n        {\n            _execute = OnExecute;\n            _canExecute = CanExecute;\n        }\n\n        public DelegateCommand(Action OnExecute, bool CanExecute = true)\n        {\n            _execute = O => OnExecute?.Invoke();\n            _canExecute = CanExecute;\n        }\n\n        public bool CanExecute(object Parameter) => _canExecute;\n\n        public void Execute(object Parameter) => _execute?.Invoke(Parameter);\n\n        public void RaiseCanExecuteChanged(bool CanExecute)\n        {\n            _canExecute = CanExecute;\n\n            _syncContext.Run(() => CanExecuteChanged?.Invoke(this, EventArgs.Empty));\n        }\n\n        public event EventHandler CanExecuteChanged;\n    }\n}"
  },
  {
    "path": "src/Captura.Base/FrameExtensions.cs",
    "content": "﻿using Captura.Models;\n\nnamespace Captura\n{\n    public static class FrameExtensions\n    {\n        public static IBitmapFrame Unwrap(this IBitmapFrame Frame)\n        {\n            while (Frame is IFrameWrapper wrapper)\n            {\n                Frame = wrapper.Frame;\n            }\n\n            return Frame;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/IImageUploader.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\n\nnamespace Captura.Models\n{\n    public interface IImageUploader\n    {\n        Task<UploadResult> Upload(IBitmapImage Image, ImageFormats Format, Action<int> Progress);\n\n        Task DeleteUploadedFile(string DeleteHash);\n\n        string UploadServiceName { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/IOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Draws over a Capured image.\n    /// </summary>\n    public interface IOverlay : IDisposable\n    {\n        /// <summary>\n        /// Draws the Overlay.\n        /// </summary>\n        void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/IRecorder.cs",
    "content": "﻿using System;\n\nnamespace Captura\n{\n    /// <summary>\n    /// Carries out the process of recording Audio and/or Video.\n    /// </summary>\n    public interface IRecorder : IDisposable\n    {\n        /// <summary>\n        /// Start Recording.\n        /// </summary>\n        void Start();\n\n        /// <summary>\n        /// Stop Recording.\n        /// </summary>\n        void Stop();\n\n        /// <summary>\n        /// Fired when an error occurs.\n        /// </summary>\n        event Action<Exception> ErrorOccurred;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/IScreen.cs",
    "content": "﻿using System.Drawing;\n\nnamespace Captura.Video\n{\n    public interface IScreen\n    {\n        Rectangle Rectangle { get; }\n\n        string DeviceName { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/IWindow.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    public interface IWindow\n    {\n        bool IsAlive { get; }\n\n        bool IsVisible { get; }\n\n        bool IsMaximized { get; }\n\n        IntPtr Handle { get; }\n\n        string Title { get; }\n\n        Rectangle Rectangle { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/IBitmapFrame.cs",
    "content": "﻿using System;\n\nnamespace Captura\n{\n    public interface IBitmapFrame : IDisposable\n    {\n        int Width { get; }\n\n        int Height { get; }\n\n        void CopyTo(byte[] Buffer);\n\n        void CopyTo(IntPtr Buffer);\n\n        TimeSpan Timestamp { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/IBitmapImage.cs",
    "content": "﻿using System;\nusing System.IO;\n\nnamespace Captura\n{\n    public interface IBitmapImage : IDisposable\n    {\n        int Width { get; }\n\n        int Height { get; }\n\n        void Save(string FileName, ImageFormats Format);\n\n        void Save(Stream Stream, ImageFormats Format);\n\n        // Assume 32bpp rgba\n        //IntPtr Map(bool Read, bool Write);\n\n        //void Unmap();\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/IBitmapLoader.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura\n{\n    public interface IBitmapLoader : IDisposable\n    {\n        IBitmapImage CreateBitmapBgr32(Size Size, IntPtr MemoryData, int Stride);\n\n        IBitmapImage LoadBitmap(string FileName);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/IEditableFrame.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura\n{\n    public interface IEditableFrame : IBitmapLoader\n    {\n        float Width { get; }\n        float Height { get; }\n\n        void DrawImage(IBitmapImage Image, RectangleF? Region, int Opacity = 100);\n\n        void DrawLine(Point Start, Point End, Color Color, float Width);\n\n        void DrawArrow(Point Start, Point End, Color Color, float Width);\n\n        void FillRectangle(Color Color, RectangleF Rectangle);\n\n        void FillRectangle(Color Color, RectangleF Rectangle, int CornerRadius);\n\n        void DrawRectangle(Color Color, float StrokeWidth, RectangleF Rectangle);\n\n        void DrawRectangle(Color Color, float StrokeWidth, RectangleF Rectangle, int CornerRadius);\n\n        void FillEllipse(Color Color, RectangleF Rectangle);\n\n        void DrawEllipse(Color Color, float StrokeWidth, RectangleF Rectangle);\n\n        IFont GetFont(string FontFamily, int Size);\n\n        SizeF MeasureString(string Text, IFont Font);\n\n        void DrawString(string Text, IFont Font, Color Color, RectangleF LayoutRectangle);\n\n        IBitmapFrame GenerateFrame(TimeSpan Timestamp);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/IFont.cs",
    "content": "﻿using System;\n\nnamespace Captura\n{\n    public interface IFont : IDisposable\n    {\n        /// <summary>\n        /// Font Size in Device Independent Pixels\n        /// </summary>\n        int Size { get; }\n\n        string FontFamily { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/IFrameWrapper.cs",
    "content": "﻿namespace Captura.Models\n{\n    public interface IFrameWrapper\n    {\n        IBitmapFrame Frame { get; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Images/IImageProvider.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura\n{\n    /// <summary>\n    /// Provides images.\n    /// Must provide in 32-bpp RGB.\n    /// </summary>\n    public interface IImageProvider : IDisposable\n    {\n        /// <summary>\n        /// Capture an image.\n        /// </summary>\n        IEditableFrame Capture();\n\n        /// <summary>\n        /// Height of Captured image.\n        /// </summary>\n        int Height { get; }\n\n        /// <summary>\n        /// Width of Captured image.\n        /// </summary>\n        int Width { get; }\n\n        Func<Point, Point> PointTransform { get; }\n\n        IBitmapFrame DummyFrame { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/IImageWriterItem.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace Captura.Models\n{\n    public interface IImageWriterItem\n    {\n        Task Save(IBitmapImage Image, ImageFormats Format, string FileName);\n\n        string Display { get; }\n\n        bool Active { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Images/IImagingSystem.cs",
    "content": "﻿using System.IO;\n\nnamespace Captura\n{\n    public interface IImagingSystem\n    {\n        IBitmapImage CreateBitmap(int Width, int Height);\n\n        IBitmapImage LoadBitmap(string FileName);\n\n        IBitmapImage LoadBitmap(Stream Stream);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/INV12Frame.cs",
    "content": "﻿namespace Captura\n{\n    public interface INV12Frame : IBitmapFrame\n    {\n        void CopyNV12To(byte[] Buffer);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/ImageFormats.cs",
    "content": "﻿namespace Captura\n{\n    public enum ImageFormats\n    {\n        Jpg,\n        Png,\n        Gif,\n        Bmp\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Images/RepeatFrame.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura\n{\n    public class RepeatFrame : IBitmapFrame, IEditableFrame\n    {\n        RepeatFrame() { }\n\n        public static RepeatFrame Instance { get; } = new RepeatFrame();\n\n        IBitmapFrame IEditableFrame.GenerateFrame(TimeSpan Timestamp) => Instance;\n\n        int IBitmapFrame.Width { get; } = -1;\n\n        float IEditableFrame.Height { get; } = -1;\n\n        TimeSpan IBitmapFrame.Timestamp { get; }\n\n        IBitmapImage IBitmapLoader.CreateBitmapBgr32(Size Size, IntPtr MemoryData, int Stride)\n        {\n            throw new NotImplementedException();\n        }\n\n        IBitmapImage IBitmapLoader.LoadBitmap(string FileName)\n        {\n            throw new NotImplementedException();\n        }\n\n        float IEditableFrame.Width { get; } = -1;\n\n        int IBitmapFrame.Height { get; } = -1;\n\n        void IDisposable.Dispose() { }\n\n        void IEditableFrame.DrawLine(Point Start, Point End, Color Color, float Width)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IEditableFrame.DrawArrow(Point Start, Point End, Color Color, float Width)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IEditableFrame.DrawImage(IBitmapImage Image, RectangleF? Region, int Opacity)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IEditableFrame.FillRectangle(Color Color, RectangleF Rectangle)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IEditableFrame.FillRectangle(Color Color, RectangleF Rectangle, int CornerRadius)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IEditableFrame.DrawRectangle(Color Color, float StrokeWidth, RectangleF Rectangle)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IEditableFrame.DrawRectangle(Color Color, float StrokeWidth, RectangleF Rectangle, int CornerRadius)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IEditableFrame.FillEllipse(Color Color, RectangleF Rectangle)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IEditableFrame.DrawEllipse(Color Color, float StrokeWidth, RectangleF Rectangle)\n        {\n            throw new NotImplementedException();\n        }\n\n        IFont IEditableFrame.GetFont(string FontFamily, int Size)\n        {\n            throw new NotImplementedException();\n        }\n\n        SizeF IEditableFrame.MeasureString(string Text, IFont Font)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IEditableFrame.DrawString(string Text, IFont Font, Color Color, RectangleF LayoutRectangle)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IBitmapFrame.CopyTo(byte[] Buffer)\n        {\n            throw new NotImplementedException();\n        }\n\n        void IBitmapFrame.CopyTo(IntPtr Buffer)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Modifiers.cs",
    "content": "using System;\n\nnamespace Captura.Hotkeys\n{\n    [Flags]\n    public enum Modifiers\n    {\n        None,\n        Alt = 1,\n        Ctrl = 2,\n        Shift = 4\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Notification/INotification.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Captura\n{\n    public interface INotification\n    {\n        int Progress { get; }\n\n        string PrimaryText { get; }\n\n        string SecondaryText { get; }\n\n        bool Finished { get; }\n\n        IEnumerable<NotificationAction> Actions { get; }\n\n        void RaiseClick();\n\n        void Remove();\n\n        event Action RemoveRequested;\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Notification/NotificationAction.cs",
    "content": "﻿using System;\nusing System.Windows.Input;\n\nnamespace Captura\n{\n    public class NotificationAction\n    {\n        public NotificationAction()\n        {\n            ClickCommand = new DelegateCommand(() => Click?.Invoke());\n        }\n\n        public string Color { get; set; }\n\n        public string Icon { get; set; }\n\n        public string Name { get; set; }\n\n        public ICommand ClickCommand { get; }\n\n        public event Action Click;\n    }\n}"
  },
  {
    "path": "src/Captura.Base/NotifyPropertyChanged.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Runtime.CompilerServices;\n\nnamespace Captura\n{\n    public class NotifyPropertyChanged : INotifyPropertyChanged\n    {\n        public event PropertyChangedEventHandler PropertyChanged;\n\n        protected void RaisePropertyChanged(string PropertyName)\n        {\n            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));\n        }\n\n        protected void OnPropertyChanged([CallerMemberName] string PropertyName = null)\n        {\n            RaisePropertyChanged(PropertyName);\n        }\n\n        protected void RaiseAllChanged()\n        {\n            RaisePropertyChanged(\"\");\n        }\n\n        protected bool Set<T>(ref T Field, T Value, [CallerMemberName] string PropertyName = null)\n        {\n            if (EqualityComparer<T>.Default.Equals(Field, Value))\n                return false;\n\n            Field = Value;\n\n            RaisePropertyChanged(PropertyName);\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Recent/IRecentItem.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Windows.Input;\n\nnamespace Captura.Models\n{\n    public interface IRecentItem\n    {\n        string Display { get; }\n\n        string Icon { get; }\n\n        string IconColor { get; }\n\n        bool IsSaving { get; }\n\n        event Action RemoveRequested;\n\n        ICommand ClickCommand { get; }\n        ICommand RemoveCommand { get; }\n\n        IEnumerable<RecentAction> Actions { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Recent/IRecentList.cs",
    "content": "﻿using System;\nusing System.Collections.ObjectModel;\n\nnamespace Captura.Models\n{\n    public interface IRecentList : IDisposable\n    {\n        void Add(IRecentItem RecentItem);\n\n        ReadOnlyObservableCollection<IRecentItem> Items { get; }\n\n        void Clear();\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Recent/RecentAction.cs",
    "content": "﻿using System;\nusing System.Windows.Input;\n\nnamespace Captura.Models\n{\n    public class RecentAction\n    {\n        public RecentAction(string Name, string Icon, Action OnClick)\n        {\n            this.Name = Name;\n            this.Icon = Icon;\n\n            ClickCommand = new DelegateCommand(() => OnClick?.Invoke());\n        }\n\n        public string Name { get; set; }\n\n        public string Icon { get; }\n\n        public ICommand ClickCommand { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/Binder.cs",
    "content": "using System;\nusing Ninject.Modules;\n\nnamespace Captura\n{\n    class Binder : NinjectModule, IBinder\n    {\n        static int _currentIndex;\n        readonly int _index;\n        readonly IModule _module;\n\n        public Binder(IModule Module)\n        {\n            _index = _currentIndex++;\n            _module = Module;\n        }\n\n        public void BindSingleton<T>()\n        {\n            Bind<T>().ToSelf().InSingletonScope();\n        }\n\n        public void Bind<TFrom, TTarget>(bool Singleton = true) where TTarget : TFrom\n        {\n            var binding = Bind<TFrom>().To<TTarget>();\n\n            if (Singleton)\n                binding.InSingletonScope();\n        }\n\n        public void Bind<T>(Func<T> Function, bool Singleton = true)\n        {\n            var binding = Bind<T>().ToMethod(M => Function());\n\n            if (Singleton)\n                binding.InSingletonScope();\n        }\n\n        public override void Load()\n        {\n            _module.OnLoad(this);\n        }\n\n        public T Get<T>() => ServiceProvider.Get<T>();\n\n        public override string Name => $\"Module{_index}\";\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IAudioPlayer.cs",
    "content": "﻿namespace Captura.Audio\n{\n    public interface IAudioPlayer\n    {\n        void Play(SoundKind SoundKind);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IBinder.cs",
    "content": "using System;\n\nnamespace Captura\n{\n    public interface IBinder\n    {\n        void BindSingleton<T>();\n        void Bind<TFrom, TTarget>(bool Singleton = true) where TTarget : TFrom;\n        void Bind<T>(Func<T> Function, bool Singleton = true);\n\n        T Get<T>();\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IClipboardService.cs",
    "content": "﻿namespace Captura\n{\n    public interface IClipboardService\n    {\n        void SetText(string Text);\n\n        string GetText();\n\n        bool HasText { get; }\n\n        void SetImage(IBitmapImage Image);\n\n        IBitmapImage GetImage();\n\n        bool HasImage { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IDialogService.cs",
    "content": "﻿namespace Captura.Models\n{\n    public interface IDialogService\n    {\n        string PickFolder(string Current, string Description);\n\n        string PickFile(string InitialFolder, string Description);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IFpsManager.cs",
    "content": "﻿namespace Captura.Models\n{\n    public interface IFpsManager\n    {\n        void OnFrame();\n\n        int Fps { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IIconSet.cs",
    "content": "﻿// ReSharper disable UnusedMember.Global\nnamespace Captura\n{\n    public interface IIconSet\n    {\n        string Add { get; }\n\n        string Arrow { get; }\n\n        string Back { get; }\n\n        string Border { get; }\n\n        string Brightness { get; }\n\n        string Brush { get; }\n\n        string Camera { get; }\n\n        string Check { get; }\n\n        string ClearNotifications { get; }\n\n        string Clipboard { get; }\n\n        string Close { get; }\n\n        string Code { get; }\n\n        string Collapse { get; }\n\n        string Contrast { get; }\n\n        string Crop { get; }\n\n        string Cursor { get; }\n\n        string Delete { get; }\n\n        string Dollar { get; }\n\n        string DoubleDown { get; }\n\n        string Download { get; }\n\n        string Ellipse { get; }\n\n        string Eraser { get; }\n\n        string Error { get; }\n\n        string Expand { get; }\n\n        string Expander { get; }\n\n        string Folder { get; }\n\n        string Font { get; }\n\n        string Forward { get; }\n\n        string Game { get; }\n\n        string GitHub { get; }\n\n        string Hand { get; }\n\n        string Help { get; }\n\n        string History { get; }\n\n        string Home { get; }\n\n        string Image { get; }\n\n        string Keyboard { get; }\n\n        string Line { get; }\n\n        string Link { get; }\n\n        string Mic { get; }\n\n        string Minimize { get; }\n\n        string Minus { get; }\n\n        string More { get; }\n\n        string MultipleMonitor { get; }\n\n        string NewFile { get; }\n\n        string NoVideo { get; }\n\n        string Opacity { get; }\n\n        string OpenFile { get; }\n\n        string Music { get; }\n\n        string Pause { get; }\n\n        string PayPal { get; }\n\n        string Pencil { get; }\n\n        string Play { get; }\n\n        string Plus { get; }\n\n        string Record { get; }\n\n        string Rectangle { get; }\n\n        string Redo { get; }\n\n        string Refresh { get; }\n\n        string Region { get; }\n\n        string Restore { get; }\n\n        string RotateLeft { get; }\n\n        string RotateRight { get; }\n\n        string RoundCorner { get; }\n\n        string Save { get; }\n\n        string Screen { get; }\n\n        string Select { get; }\n\n        string Settings { get; }\n\n        string SnapToWindow { get; }\n\n        string Speaker { get; }\n\n        string Stop { get; }\n\n        string StrokeEraser { get; }\n\n        string Undo { get; }\n\n        string Timer { get; }\n\n        string Translate { get; }\n\n        string Trim { get; }\n\n        string Twitch { get; }\n\n        string Upload { get; }\n\n        string Video { get; }\n\n        string VideoFile { get; }\n\n        string Visibility { get; }\n\n        string VisibilityHide { get; }\n\n        string Web { get; }\n\n        string Webcam { get; }\n\n        string Window { get; }\n\n        string YouTube { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IMainWindow.cs",
    "content": "﻿namespace Captura.Models\n{\n    public interface IMainWindow\n    {\n        bool IsVisible { get; set; }\n\n        bool IsMinimized { get; set; }\n\n        void EditImage(string FileName);\n\n        void TrimMedia(string FileName);\n\n        void UploadToYouTube(string FileName);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Services/IMessageProvider.cs",
    "content": "﻿using System;\n\nnamespace Captura.Models\n{\n    public interface IMessageProvider\n    {\n        void ShowError(string Message, string Header = null);\n\n        bool ShowYesNo(string Message, string Title);\n\n        void ShowException(Exception Exception, string Message, bool Blocking = false);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Services/IModule.cs",
    "content": "using System;\n\nnamespace Captura\n{\n    public interface IModule : IDisposable\n    {\n        void OnLoad(IBinder Binder);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IPlatformServices.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing Captura.Video;\n\nnamespace Captura\n{\n    public interface IPlatformServices\n    {\n        IEnumerable<IScreen> EnumerateScreens();\n\n        IEnumerable<IWindow> EnumerateWindows();\n\n        IEnumerable<IWindow> EnumerateAllWindows();\n\n        IWindow GetWindow(IntPtr Handle);\n\n        IWindow DesktopWindow { get; }\n\n        IWindow ForegroundWindow { get; }\n\n        Rectangle DesktopRectangle { get; }\n\n        bool DeleteFile(string FilePath);\n\n        Point CursorPosition { get; }\n\n        IBitmapImage CaptureTransparent(IWindow Window, bool IncludeCursor = false);\n\n        IBitmapImage Capture(Rectangle Region, bool IncludeCursor = false);\n\n        IImageProvider GetRegionProvider(Rectangle Region,\n            bool IncludeCursor,\n            Func<Point> LocationFunction = null);\n\n        IImageProvider GetWindowProvider(IWindow Window, bool IncludeCursor);\n\n        IImageProvider GetScreenProvider(IScreen Screen, bool IncludeCursor, bool StepsMode);\n\n        IImageProvider GetAllScreensProvider(bool IncludeCursor, bool StepsMode);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IPreviewWindow.cs",
    "content": "﻿using System;\n\nnamespace Captura.Video\n{\n    public interface IPreviewWindow : IDisposable\n    {\n        void Display(IBitmapFrame Frame);\n\n        void Show();\n\n        bool IsVisible { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IRegionProvider.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    public interface IRegionProvider\n    {\n        bool SelectorVisible { get; set; }\n\n        Rectangle SelectedRegion { get; set; }\n\n        IVideoItem VideoSource { get; }\n\n        IntPtr Handle { get; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Services/ISystemTray.cs",
    "content": "﻿namespace Captura.Models\n{\n    public interface ISystemTray\n    {\n        void ShowScreenShotNotification(string FilePath);\n\n        void HideNotification();\n\n        void ShowNotification(INotification Notification);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Services/IVideoSourcePicker.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    public interface IVideoSourcePicker\n    {\n        IWindow PickWindow(Predicate<IWindow> Filter = null);\n\n        IScreen PickScreen();\n\n        Rectangle? PickRegion();\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IWebCamProvider.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Captura.Webcam\n{\n    public interface IWebCamProvider\n    {\n        IEnumerable<IWebcamItem> GetSources();\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Services/IWebcamCapture.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Video;\n\nnamespace Captura.Webcam\n{\n    public interface IWebcamCapture : IDisposable\n    {\n        IBitmapImage Capture(IBitmapLoader BitmapLoader);\n\n        int Width { get; }\n\n        int Height { get; }\n\n        void UpdatePreview(IWindow Window, Rectangle Location);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/IWebcamItem.cs",
    "content": "using System;\n\nnamespace Captura.Webcam\n{\n    public interface IWebcamItem\n    {\n        string Name { get; }\n\n        IWebcamCapture BeginCapture(Action OnClick);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Services/ServiceProvider.cs",
    "content": "using Captura.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing Ninject;\n\nnamespace Captura\n{\n    public static class ServiceProvider\n    {\n        public const string CapturaPathConstant = \"%CAPTURA_PATH%\";\n\n        static string _settingsDir;\n\n        public static string SettingsDir\n        {\n            get\n            {\n                if (_settingsDir == null)\n                {\n                    var localSettings = Path.Combine(AppDir, \"Settings\");\n\n                    if (Directory.Exists(localSettings))\n                    {\n                        _settingsDir = localSettings;\n                    }\n                    else\n                    {\n                        var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);\n\n                        _settingsDir = Path.Combine(appDataPath, nameof(Captura));\n                    }\n                }\n\n                if (!Directory.Exists(_settingsDir))\n                    Directory.CreateDirectory(_settingsDir);\n\n                return _settingsDir;\n            }\n            set\n            {\n                if (string.IsNullOrWhiteSpace(value))\n                    return;\n\n                value = value.Replace(CapturaPathConstant, AppDir);\n\n                _settingsDir = value;\n\n                if (!Directory.Exists(_settingsDir))\n                    Directory.CreateDirectory(_settingsDir);\n            }\n        }\n\n        static IKernel Kernel { get; } = new StandardKernel();\n\n        static readonly List<IModule> LoadedModules = new List<IModule>();\n\n        public static void LoadModule(IModule Module)\n        {\n            Kernel.Load(new Binder(Module));\n\n            LoadedModules.Add(Module);\n        }\n\n        /// <summary>\n        /// To be called on App Exit\n        /// </summary>\n        public static void Dispose()\n        {\n            LoadedModules.ForEach(M => M.Dispose());\n\n            // Singleton objects will be disposed by Kernel\n            Kernel.Dispose();\n        }\n\n        public static T Get<T>() => Kernel.Get<T>();\n        \n        public static void LaunchFile(ProcessStartInfo StartInfo)\n        {\n            try { Process.Start(StartInfo.FileName); }\n            catch (Win32Exception e) when (e.NativeErrorCode == 2)\n            {\n                MessageProvider.ShowError($\"Could not find file: {StartInfo.FileName}\");\n            }\n            catch (Exception e)\n            {\n                MessageProvider.ShowException(e, $\"Could not open file: {StartInfo.FileName}\");\n            }\n        }\n\n        public static IMessageProvider MessageProvider => Get<IMessageProvider>();\n\n        public static Version AppVersion => Assembly.GetEntryAssembly()?.GetName().Version;\n\n        public static string AppDir\n        {\n            get\n            {\n                var location = Assembly.GetEntryAssembly()?.Location;\n\n                return location == null ? \"\" : Path.GetDirectoryName(location);\n            }\n        }\n\n        public static string LibDir => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n\n        public static bool FileExists(string FileName)\n        {\n            return new[] { LibDir, AppDir }\n                       .Where(M => M != null)\n                       .Any(M => File.Exists(Path.Combine(M, FileName))) || File.Exists(FileName);\n        }\n\n        /// <summary>\n        /// Binds both as Inteface as Class\n        /// </summary>\n        public static void BindAsInterfaceAndClass<TInterface, TClass>(this IBinder Binder) where TClass : TInterface\n        {\n            Binder.BindSingleton<TClass>();\n\n            // ReSharper disable once ConvertClosureToMethodGroup\n            Binder.Bind<TInterface>(() => Get<TClass>());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Settings/Alignment.cs",
    "content": "﻿namespace Captura\n{\n    public enum Alignment\n    {\n        Start,\n        Center,\n        End\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Settings/AudioSettings.cs",
    "content": "﻿namespace Captura.Audio\n{\n    public class AudioSettings : PropertyStore\n    {\n        public bool SeparateFilePerSource\n        {\n            get => Get(false);\n            set => Set(value);\n        }\n\n        public bool RecordMicrophone\n        {\n            get => Get(false);\n            set => Set(value);\n        }\n\n        public string Microphone\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public bool RecordSpeaker\n        {\n            get => Get(false);\n            set => Set(value);\n        }\n\n        public string Speaker\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public int Quality\n        {\n            get => Get(80);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Settings/MouseOverlaySettings.cs",
    "content": "﻿using System.Drawing;\n\nnamespace Captura\n{\n    public class MouseOverlaySettings : PropertyStore\n    {\n        public bool Display\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n\n        public int Radius\n        {\n            get => Get(25);\n            set => Set(value);\n        }\n\n        public Color Color\n        {\n            get => Get(Color.FromArgb(255, 235, 59));\n            set => Set(value);\n        }\n\n        public int BorderThickness\n        {\n            get => Get<int>();\n            set => Set(value);\n        }\n\n        public Color BorderColor\n        {\n            get => Get(Color.Black);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Settings/PositionedOverlaySettings.cs",
    "content": "﻿// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global\nnamespace Captura.Video\n{\n    public class PositionedOverlaySettings : PropertyStore\n    {\n        public Alignment HorizontalAlignment\n        {\n            get => Get(Alignment.Start);\n            set => Set(value);\n        }\n\n        public Alignment VerticalAlignment\n        {\n            get => Get(Alignment.End);\n            set => Set(value);\n        }\n\n        public int X\n        {\n            get => Get(80);\n            set => Set(value);\n        }\n\n        public int Y\n        {\n            get => Get(100);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Settings/PropertyStore.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Runtime.CompilerServices;\n\nnamespace Captura\n{\n    public abstract class PropertyStore : NotifyPropertyChanged\n    {\n        readonly Dictionary<string, object> _dictionary = new Dictionary<string, object>();\n\n        protected T Get<T>(T Default = default, [CallerMemberName] string PropertyName = \"\")\n        {\n            lock (_dictionary)\n            {\n                if (_dictionary.TryGetValue(PropertyName, out var obj) && obj is T val)\n                {\n                    return val;\n                }\n            }\n\n            return Default;\n        }\n\n        protected void Set<T>(T Value, [CallerMemberName] string PropertyName = \"\")\n        {\n            lock (_dictionary)\n            {\n                if (_dictionary.ContainsKey(PropertyName))\n                {\n                    _dictionary[PropertyName] = Value;\n                }\n                else _dictionary.Add(PropertyName, Value);\n            }\n\n            OnPropertyChanged(PropertyName);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Settings/ProxySettings.cs",
    "content": "﻿using System.Net;\n\nnamespace Captura\n{\n    public enum ProxyType\n    {\n        None,\n        System,\n        Manual\n    }\n\n    public class ProxySettings : PropertyStore\n    {\n        public IWebProxy GetWebProxy()\n        {\n            if (Type == ProxyType.None)\n                return null;\n\n            IWebProxy proxy;\n\n            if (Type == ProxyType.Manual && !string.IsNullOrWhiteSpace(Host) && Port > 0)\n            {\n                proxy = new WebProxy(Host, Port);\n            }\n            else proxy = WebRequest.GetSystemWebProxy();\n\n            if (Authenticate && !string.IsNullOrWhiteSpace(UserName) && !string.IsNullOrWhiteSpace(Password))\n            {\n                proxy.Credentials = new NetworkCredential(UserName, Password);\n            }\n\n            return proxy;\n        }\n\n        public ProxyType Type\n        {\n            get => Get(ProxyType.System);\n            set => Set(value);\n        }\n\n        public string Host\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public int Port\n        {\n            get => Get<int>();\n            set => Set(value);\n        }\n\n        public bool Authenticate\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n\n        public string UserName\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public string Password\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Settings/StepsSettings.cs",
    "content": "﻿namespace Captura\n{\n    public class StepsSettings : PropertyStore\n    {\n        public string Writer\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public bool IncludeScrolls\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Settings/TextOverlaySettings.cs",
    "content": "﻿using System.Drawing;\n// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global\n\nnamespace Captura.Video\n{\n    public class TextOverlaySettings : PositionedOverlaySettings\n    {\n        public bool Display\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n\n        public string FontFamily\n        {\n            get => Get(\"Arial\");\n            set => Set(value);\n        }\n\n        public int FontSize\n        {\n            get => Get(50);\n            set => Set(value);\n        }\n\n        public Color FontColor\n        {\n            get => Get(Color.White);\n            set => Set(value);\n        }\n\n        public Color BackgroundColor\n        {\n            get => Get(Color.Teal);\n            set => Set(value);\n        }\n\n        public int HorizontalPadding\n        {\n            get => Get(15);\n            set => Set(value);\n        }\n\n        public int VerticalPadding\n        {\n            get => Get(15);\n            set => Set(value);\n        }\n\n        public int CornerRadius\n        {\n            get => Get(30);\n            set => Set(value);\n        }\n\n        public int BorderThickness\n        {\n            get => Get<int>();\n            set => Set(value);\n        }\n\n        public Color BorderColor\n        {\n            get => Get(Color.FromArgb(158, 158, 158));\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Settings/VideoSettings.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class VideoSettings : PropertyStore\n    {\n        public string WriterKind\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n        \n        public string Writer\n        {\n            get => Get<string>();\n            set => Set(value);\n        }\n\n        public bool PostConvert\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n\n        public string PostWriter\n        {\n            get => Get<string>();\n            set => Set(value);\n        }\n        \n        public string SourceKind\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public string Source\n        {\n            get => Get<string>();\n            set => Set(value);\n        }\n\n        public string Webcam\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public int Quality\n        {\n            get => Get(70);\n            set => Set(value);\n        }\n\n        public int FrameRate\n        {\n            get => Get(20);\n            set => Set(value);\n        }\n\n        public bool FpsLimit\n        {\n            get => Get(true);\n            set\n            {\n                Set(value);\n\n                if (value && FrameRate > 30)\n                {\n                    FrameRate = 30;\n                }\n            }\n        }\n\n        public RecorderMode RecorderMode\n        {\n            get => Get(RecorderMode.Video);\n            set => Set(value);\n        }\n\n        public int ReplayDuration\n        {\n            get => Get(20);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/SoundKind.cs",
    "content": "﻿namespace Captura.Audio\n{\n    public enum SoundKind\n    {\n        Start,\n        Stop,\n        Pause,\n        Shot,\n        Error,\n        Notification\n    }\n}"
  },
  {
    "path": "src/Captura.Base/SyncContextManager.cs",
    "content": "﻿using System;\nusing System.Threading;\n\nnamespace Captura.Models\n{\n    public class SyncContextManager\n    {\n        readonly SynchronizationContext _syncContext = SynchronizationContext.Current;\n\n        public void Run(Action Action, bool Async = false)\n        {\n            if (_syncContext == null)\n            {\n                Action();\n            }\n            else if (Async)\n            {\n                _syncContext.Post(D => Action(), null);\n            }\n            else _syncContext.Send(D => Action(), null);\n        }\n\n        public T Run<T>(Func<T> Action)\n        {\n            if (_syncContext == null)\n            {\n                return Action();\n            }\n\n            T result = default;\n\n            _syncContext.Send(D => result = Action(), null);\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/UploadResult.cs",
    "content": "﻿namespace Captura.Models\n{\n    public class UploadResult\n    {\n        public string Url { get; set; }\n\n        public string DeleteLink { get; set; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Video/IVideoConverter.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\n\nnamespace Captura.Video\n{\n    public interface IVideoConverter\n    {\n        string Name { get; }\n\n        string Extension { get; }\n\n        Task StartAsync(VideoConverterArgs Args, IProgress<int> Progress);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Video/IVideoFileWriter.cs",
    "content": "﻿using System;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Creates a video from individual frames and writes them to a file.\n    /// </summary>\n    public interface IVideoFileWriter : IDisposable\n    {\n        /// <summary>\n        /// Writes an Image frame.\n        /// </summary>\n        /// <param name=\"Image\">The Image frame to write.</param>\n        void WriteFrame(IBitmapFrame Image);\n        \n        /// <summary>\n        /// Gets whether audio is supported.\n        /// </summary>\n        bool SupportsAudio { get; }\n                \n        /// <summary>\n        /// Write audio block to Audio Stream.\n        /// </summary>\n        /// <param name=\"Buffer\">Buffer containing audio data.</param>\n        /// <param name=\"Length\">Length of audio data in bytes.</param>\n        void WriteAudio(byte[] Buffer, int Offset, int Length);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Video/IVideoItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    /// <summary>\n    /// Items to show in Video Source List.\n    /// </summary>\n    public interface IVideoItem\n    {\n        string Name { get; }\n\n        IImageProvider GetImageProvider(bool IncludeCursor);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Video/IVideoSourceProvider.cs",
    "content": "namespace Captura.Video\n{\n    public interface IVideoSourceProvider\n    {\n        string Name { get; }\n\n        string Description { get; }\n\n        string Icon { get; }\n\n        IVideoItem Source { get; }\n\n        bool SupportsStepsMode { get; }\n\n        IBitmapImage Capture(bool IncludeCursor);\n\n        bool OnSelect();\n\n        void OnUnselect();\n\n        string Serialize();\n\n        bool Deserialize(string Serialized);\n\n        bool ParseCli(string Arg);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Video/IVideoWriterItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    /// <summary>\n    /// Items to show in Video Writers list.\n    /// </summary>\n    public interface IVideoWriterItem\n    {\n        // file extension including the leading dot\n        string Extension { get; }\n\n        string Description { get; }\n\n        IVideoFileWriter GetVideoFileWriter(VideoWriterArgs Args);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Video/IVideoWriterProvider.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Captura.Video\n{\n    public interface IVideoWriterProvider : IEnumerable<IVideoWriterItem>\n    {\n        string Name { get; }\n\n        string Description { get; }\n\n        IVideoWriterItem ParseCli(string Cli);\n    }\n}"
  },
  {
    "path": "src/Captura.Base/Video/RecorderMode.cs",
    "content": "﻿namespace Captura\n{\n    public enum RecorderMode\n    {\n        //AudioOnly,\n        Video,\n        //Streaming,\n        Steps,\n        Replay\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Video/VideoConverterParams.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class VideoConverterArgs : VideoWriterArgs\n    {\n        public string InputFile { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Base/Video/VideoWriterArgs.cs",
    "content": "﻿using Captura.Audio;\n\nnamespace Captura.Video\n{\n    public class VideoWriterArgs\n    {\n        public string FileName { get; set; }\n        public IImageProvider ImageProvider { get; set; }\n        public int FrameRate { get; set; } = 15;\n        public int VideoQuality { get; set; } = 70;\n        public int AudioQuality { get; set; } = 50;\n        public IAudioProvider AudioProvider { get; set; }\n    }\n}"
  },
  {
    "path": "src/Captura.Base/WindowClosedException.cs",
    "content": "﻿using System;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Thrown when a closed window is used.\n    /// </summary>\n    public class WindowClosedException : Exception { }\n}"
  },
  {
    "path": "src/Captura.Console/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <startup>\n    <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.7.2\" />\n  </startup>\n  <runtime>\n    <assemblyBinding xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n      <probing privatePath=\"lib\"/>\n    </assemblyBinding>\n  </runtime>\n</configuration>\n"
  },
  {
    "path": "src/Captura.Console/Captura.Console.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Captura</RootNamespace>\n    <AssemblyName>captura-cli</AssemblyName>\n    <TargetFramework>net472</TargetFramework>\n    <OutputPath>bin\\$(Configuration)\\</OutputPath>\n    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\n    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup>\n    <ApplicationIcon>..\\Captura\\Images\\Captura.ico</ApplicationIcon>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"System.Windows.Forms\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"App.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Core\\Captura.Core.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Fakes\\Captura.Fakes.csproj\" />\n    <ProjectReference Include=\"..\\Captura.FFmpeg\\Captura.FFmpeg.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Loc\\Captura.Loc.csproj\" />\n    <ProjectReference Include=\"..\\Captura.MouseKeyHook\\Captura.MouseKeyHook.csproj\" />\n    <ProjectReference Include=\"..\\Captura.SharpAvi\\Captura.SharpAvi.csproj\" />\n    <ProjectReference Include=\"..\\Screna\\Screna.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"..\\Captura\\Images\\Captura.ico\">\n      <Link>Captura.ico</Link>\n    </Content>\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"CommandLineParser\" Version=\"2.2.1\" />\n  </ItemGroup>\n  <Import Project=\"../PostBuild.targets\" />\n</Project>"
  },
  {
    "path": "src/Captura.Console/CmdOptions/CommonCmdOptions.cs",
    "content": "﻿using CommandLine;\n\nnamespace Captura\n{\n    abstract class CommonCmdOptions\n    {\n        [Option(\"cursor\", HelpText = \"Include Cursor in Recording (default = false).\")]\n        public bool Cursor { get; set; }\n\n        [Option(\"source\", Default = \"\", HelpText = \"Video source\")]\n        public string Source { get; set; }\n\n        [Option('f', \"file\", HelpText = \"Output file path\")]\n        public string FileName { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Console/CmdOptions/FFMpegCmdOptions.cs",
    "content": "﻿using CommandLine;\n\nnamespace Captura\n{\n    [Verb(\"ffmpeg\", HelpText = \"Manage FFmpeg\")]\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class FFmpegCmdOptions : ICmdlineVerb\n    {\n        [Option(\"install\", HelpText = \"Install FFmpeg to specified folder.\")]\n        public string Install { get; set; }\n\n        public void Run()\n        {\n            var ffmpegManager = ServiceProvider.Get<FFmpegConsoleManager>();\n\n            // Need to Wait instead of await otherwise the process will exit\n            ffmpegManager.Run(this).Wait();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Console/CmdOptions/ICmdlineVerb.cs",
    "content": "﻿namespace Captura\n{\n    interface ICmdlineVerb\n    {\n        void Run();\n    }\n}\n"
  },
  {
    "path": "src/Captura.Console/CmdOptions/ListCmdOptions.cs",
    "content": "﻿using CommandLine;\n\nnamespace Captura\n{\n    [Verb(\"list\", HelpText = \"Display available video sources, encoders, audio sources, etc.\")]\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class ListCmdOptions : ICmdlineVerb\n    {\n        public void Run()\n        {\n            var lister = ServiceProvider.Get<ConsoleLister>();\n\n            lister.List();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Console/CmdOptions/ShotCmdOptions.cs",
    "content": "﻿using System.Collections.Generic;\nusing CommandLine;\nusing CommandLine.Text;\n\nnamespace Captura\n{\n    [Verb(\"shot\", HelpText = \"Take Screenshots\")]\n    class ShotCmdOptions : CommonCmdOptions, ICmdlineVerb\n    {\n        [Usage]\n        public static IEnumerable<Example> Examples\n        {\n            get\n            {\n                yield return new Example(\"Take screenshot containing cursor\", new ShotCmdOptions\n                {\n                    Cursor = true\n                });\n\n                yield return new Example(\"Save screenshot to out.png\", new ShotCmdOptions\n                {\n                    FileName = \"out.png\"\n                });\n\n                yield return new Example(\"Take screenshot of second screen\", new ShotCmdOptions\n                {\n                    Source = \"screen:1\"\n                });\n            }\n        }\n\n        public void Run()\n        {\n            using var manager = ServiceProvider.Get<ConsoleManager>();\n            manager.Shot(this);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Console/CmdOptions/StartCmdOptions.cs",
    "content": "﻿using System.Collections.Generic;\nusing CommandLine;\nusing CommandLine.Text;\n\n// ReSharper disable MemberCanBePrivate.Global\n// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global\n// ReSharper disable UnusedAutoPropertyAccessor.Global\n\nnamespace Captura\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    [Verb(\"start\", HelpText = \"Start Recording\")]\n    class StartCmdOptions : CommonCmdOptions, ICmdlineVerb\n    {\n        [Option(\"delay\", HelpText = \"Milliseconds to wait before starting recording.\")]\n        public int Delay { get; set; }\n\n        [Option('t', \"length\", HelpText = \"Length of Recording in seconds.\")]\n        public int Length { get; set; }\n\n        [Option('y', HelpText = \"Overwrite existing file\")]\n        public bool Overwrite { get; set; }\n        \n        [Option(\"keys\", HelpText = \"Include Keystrokes in Recording (default = false).\")]\n        public bool Keys { get; set; }\n\n        [Option(\"clicks\", HelpText = \"Include Mouse Clicks in Recording (default = false).\")]\n        public bool Clicks { get; set; }\n\n        [Option(\"mic\", Default = -1, HelpText = \"Index of Microphone source. Default = -1 (No Microphone).\")]\n        public int Microphone { get; set; }\n\n        [Option(\"speaker\", Default = -1, HelpText = \"Index of Speaker output source. Default = -1 (No Speaker).\")]\n        public int Speaker { get; set; }\n\n        [Option('r', \"framerate\", HelpText = \"Recording frame rate.\")]\n        public int? FrameRate { get; set; }\n\n        [Option(\"encoder\", Default = \"\", HelpText = \"Video encoder to use.\")]\n        public string Encoder { get; set; }\n\n        [Option(\"vq\", HelpText = \"Video Quality\")]\n        public int? VideoQuality { get; set; }\n\n        [Option(\"aq\", HelpText = \"Audio Quality\")]\n        public int? AudioQuality { get; set; }\n\n        [Option(\"webcam\", Default = -1, HelpText = \"Webcam to use. Default = -1 (No Webcam)\")]\n        public int Webcam { get; set; }\n\n        [Option(\"replay\", HelpText = \"Capture last n seconds.\")]\n        public int? Replay { get; set; }\n\n        [Option(\"settings\", HelpText = \"Settings file to use for overlay settings, ffmpeg path and output path\")]\n        public string Settings { get; set; }\n\n        [Usage]\n        public static IEnumerable<Example> Examples\n        {\n            get\n            {\n                yield return new Example(\"Record 10 seconds with cursor and keystrokes and audio from first speaker output.\", new StartCmdOptions\n                {\n                    Cursor = true,\n                    Keys = true,\n                    Length = 10,\n                    Speaker = 0\n                });\n\n                yield return new Example(\"Record specific region\", new StartCmdOptions\n                {\n                    Source = \"100,100,300,400\"\n                });\n\n                yield return new Example(\"Record as Avi to out.avi\", new StartCmdOptions\n                {\n                    Encoder = \"sharpavi:0\",\n                    FileName = \"out.avi\"\n                });\n            }\n        }\n\n        public void Run()\n        {\n            // Override settings dir\n            if (Settings != null)\n            {\n                ServiceProvider.SettingsDir = Settings;\n            }\n\n            using var manager = ServiceProvider.Get<ConsoleManager>();\n            manager.CopySettings();\n\n            manager.Start(this);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Console/CmdOptions/UploadCmdOptions.cs",
    "content": "﻿using Captura.Models;\nusing CommandLine;\nusing CommandLine.Text;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\n\nnamespace Captura\n{\n    [Verb(\"upload\", HelpText = \"Upload a file to a specified service.\")]\n    class UploadCmdOptions : ICmdlineVerb\n    {\n        [Value(0, HelpText = \"The service to upload to\")]\n        public UploadService Service { get; set; }\n\n        [Value(1, HelpText = \"The file to upload\")]\n        public string FileName { get; set; }\n\n        [Usage]\n        public static IEnumerable<Example> Examples\n        {\n            get\n            {\n                yield return new Example(\"Upload image to Imgur\", new UploadCmdOptions\n                {\n                    Service = UploadService.imgur,\n                    FileName = \"image.png\"\n                });\n            }\n        }\n\n        public void Run()\n        {\n            if (!File.Exists(FileName))\n            {\n                Console.WriteLine(\"File not found\");\n                return;\n            }\n\n            switch (Service)\n            {\n                case UploadService.imgur:\n                    var imgSystem = ServiceProvider.Get<IImagingSystem>();\n                    var img = imgSystem.LoadBitmap(FileName);\n                    var uploader = ServiceProvider.Get<IImageUploader>();\n\n                    // TODO: Show progress (on a single line)\n                    var result = uploader.Upload(img, ImageFormats.Png, P => { }).Result;\n\n                    Console.WriteLine(result.Url);\n                    break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Console/CmdOptions/UploadService.cs",
    "content": "﻿namespace Captura\n{\n    enum UploadService\n    {\n        imgur,\n        youtube\n    }\n}\n"
  },
  {
    "path": "src/Captura.Console/CmdOptions/VerbsModule.cs",
    "content": "﻿namespace Captura\n{\n    class VerbsModule : IModule\n    {\n        public void Dispose()\n        {\n        }\n\n        public void OnLoad(IBinder Binder)\n        {\n            Binder.Bind<ICmdlineVerb, StartCmdOptions>();\n            Binder.Bind<ICmdlineVerb, ShotCmdOptions>();\n            Binder.Bind<ICmdlineVerb, FFmpegCmdOptions>();\n            Binder.Bind<ICmdlineVerb, ListCmdOptions>();\n            Binder.Bind<ICmdlineVerb, UploadCmdOptions>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Console/ConsoleLister.cs",
    "content": "﻿using Captura.Audio;\nusing System.Linq;\nusing Captura.FFmpeg;\nusing Captura.SharpAvi;\nusing Captura.Webcam;\nusing static System.Console;\n\nnamespace Captura\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ConsoleLister\n    {\n        static readonly string Underline = $\"\\n{new string('-', 30)}\";\n\n        readonly WebcamModel _webcam;\n        readonly IAudioSource _audioSource;\n        readonly IPlatformServices _platformServices;\n        readonly FFmpegWriterProvider _ffmpegWriterProvider;\n        readonly SharpAviWriterProvider _sharpAviWriterProvider;\n\n        public ConsoleLister(WebcamModel Webcam,\n            IAudioSource AudioSource,\n            IPlatformServices PlatformServices,\n            FFmpegWriterProvider FfmpegWriterProvider,\n            SharpAviWriterProvider SharpAviWriterProvider)\n        {\n            _webcam = Webcam;\n            _audioSource = AudioSource;\n            _platformServices = PlatformServices;\n            _ffmpegWriterProvider = FfmpegWriterProvider;\n            _sharpAviWriterProvider = SharpAviWriterProvider;\n        }\n\n        public void List()\n        {\n            FFmpeg();\n\n            SharpAvi();\n\n            Windows();\n\n            Screens();\n\n            Audio();\n\n            Webcam();\n        }\n\n        void Webcam()\n        {\n            if (_webcam.AvailableCams.Count > 1)\n            {\n                WriteLine(\"AVAILABLE WEBCAMS\" + Underline);\n\n                for (var i = 1; i < _webcam.AvailableCams.Count; ++i)\n                {\n                    WriteLine($\"{(i - 1).ToString().PadRight(2)}: {_webcam.AvailableCams[i]}\");\n                }\n\n                WriteLine();\n            }\n        }\n\n        void Audio()\n        {\n            WriteLine($\"Audio Source: {_audioSource.Name}\");\n\n            WriteLine();\n\n            var mics = _audioSource\n                .Microphones\n                .ToArray();\n\n            var speakers = _audioSource\n                .Speakers\n                .ToArray();\n\n            // Microphones\n            if (mics.Length > 0)\n            {\n                WriteLine(\"AVAILABLE MICROPHONES\" + Underline);\n\n                for (var i = 0; i < mics.Length; ++i)\n                {\n                    WriteLine($\"{i.ToString().PadRight(2)}: {mics[i]}\");\n                }\n\n                WriteLine();\n            }\n\n            // Speakers\n            if (speakers.Length > 0)\n            {\n                WriteLine(\"AVAILABLE SPEAKER SOURCES\" + Underline);\n\n                for (var i = 0; i < speakers.Length; ++i)\n                {\n                    WriteLine($\"{i.ToString().PadRight(2)}: {speakers[i]}\");\n                }\n\n                WriteLine();\n            }\n        }\n\n        void Screens()\n        {\n            WriteLine(\"AVAILABLE SCREENS\" + Underline);\n\n            var j = 0;\n\n            // First is Full Screen, Second is Screen Picker\n            foreach (var screen in _platformServices.EnumerateScreens())\n            {\n                WriteLine($\"{j.ToString().PadRight(2)}: {screen.DeviceName}\");\n\n                ++j;\n            }\n\n            WriteLine();\n        }\n\n        void Windows()\n        {\n            WriteLine(\"AVAILABLE WINDOWS\" + Underline);\n\n            // Window Picker is skipped automatically\n            foreach (var source in _platformServices.EnumerateWindows())\n            {\n                WriteLine($\"{source.Handle.ToString().PadRight(10)}: {source.Title}\");\n            }\n\n            WriteLine();\n        }\n\n        void SharpAvi()\n        {\n            var sharpAviExists = ServiceProvider.FileExists(\"SharpAvi.dll\");\n\n            WriteLine($\"SharpAvi Available: {(sharpAviExists ? \"YES\" : \"NO\")}\");\n\n            WriteLine();\n\n            if (!sharpAviExists)\n                return;\n\n            WriteLine(\"SharpAvi ENCODERS\" + Underline);\n\n            var i = 0;\n\n            foreach (var codec in _sharpAviWriterProvider)\n            {\n                WriteLine($\"{i.ToString().PadRight(2)}: {codec}\");\n                ++i;\n            }\n\n            WriteLine();\n        }\n\n        void FFmpeg()\n        {\n            var ffmpegExists = FFmpegService.FFmpegExists;\n\n            WriteLine($\"FFmpeg Available: {(ffmpegExists ? \"YES\" : \"NO\")}\");\n\n            WriteLine();\n\n            if (!ffmpegExists)\n                return;\n\n            WriteLine(\"FFmpeg ENCODERS\" + Underline);\n\n            var i = 0;\n\n            foreach (var codec in _ffmpegWriterProvider)\n            {\n                WriteLine($\"{i.ToString().PadRight(2)}: {codec}\");\n                ++i;\n            }\n\n            WriteLine();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Console/ConsoleManager.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Windows.Forms;\nusing Captura.Audio;\nusing Captura.FFmpeg;\nusing Captura.Models;\nusing Captura.SharpAvi;\nusing Captura.Video;\nusing Captura.ViewModels;\nusing Captura.Webcam;\nusing Captura.Windows;\nusing static System.Console;\n\nnamespace Captura\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class ConsoleManager : IDisposable\n    {\n        readonly Settings _settings;\n        readonly RecordingModel _recordingModel;\n        readonly ScreenShotModel _screenShotModel;\n        readonly IEnumerable<IVideoSourceProvider> _videoSourceProviders;\n        readonly IEnumerable<IVideoWriterProvider> _videoWriterProviders;\n        readonly WebcamModel _webcamModel;\n        readonly IPlatformServices _platformServices;\n        readonly IMessageProvider _messageProvider;\n        readonly IAudioSource _audioSource;\n\n        public ConsoleManager(Settings Settings,\n            RecordingModel RecordingModel,\n            ScreenShotModel ScreenShotModel,\n            IEnumerable<IVideoSourceProvider> VideoSourceProviders,\n            IEnumerable<IVideoWriterProvider> VideoWriterProviders,\n            IPlatformServices PlatformServices,\n            WebcamModel WebcamModel,\n            IMessageProvider MessageProvider,\n            IAudioSource AudioSource)\n        {\n            _settings = Settings;\n            _recordingModel = RecordingModel;\n            _screenShotModel = ScreenShotModel;\n            _videoSourceProviders = VideoSourceProviders;\n            _videoWriterProviders = VideoWriterProviders;\n            _platformServices = PlatformServices;\n            _webcamModel = WebcamModel;\n            _messageProvider = MessageProvider;\n            _audioSource = AudioSource;\n\n            // Hide on Full Screen Screenshot doesn't work on Console\n            Settings.UI.HideOnFullScreenShot = false;\n        }\n\n        public void Dispose()\n        {\n            ServiceProvider.Dispose();\n        }\n\n        public void CopySettings()\n        {\n            // Load settings dummy\n            var dummySettings = new Settings(new FFmpegSettings(), new WindowsSettings());\n            dummySettings.Load();\n\n            _settings.WebcamOverlay = dummySettings.WebcamOverlay;\n            _settings.MousePointerOverlay = dummySettings.MousePointerOverlay;\n            _settings.Clicks = dummySettings.Clicks;\n            _settings.Keystrokes = dummySettings.Keystrokes;\n            _settings.Elapsed = dummySettings.Elapsed;\n\n            // Output Folder\n            _settings.OutPath = dummySettings.OutPath;\n\n            // FFmpeg Path\n            _settings.FFmpeg.FolderPath = dummySettings.FFmpeg.FolderPath;\n\n            foreach (var overlay in dummySettings.Censored)\n            {\n                _settings.Censored.Add(overlay);\n            }\n\n            foreach (var overlay in dummySettings.TextOverlays)\n            {\n                _settings.TextOverlays.Add(overlay);\n            }\n\n            foreach (var overlay in dummySettings.ImageOverlays)\n            {\n                _settings.ImageOverlays.Add(overlay);\n            }\n        }\n\n        public void Start(StartCmdOptions StartOptions)\n        {\n            _settings.IncludeCursor = StartOptions.Cursor;\n            _settings.Clicks.Display = StartOptions.Clicks;\n            _settings.Keystrokes.Display = StartOptions.Keys;\n\n            if (File.Exists(StartOptions.FileName))\n            {\n                if (!StartOptions.Overwrite)\n                {\n                    if (!_messageProvider\n                        .ShowYesNo(\"Output File Already Exists, Do you want to overwrite?\", \"\"))\n                        return;\n                }\n\n                File.Delete(StartOptions.FileName);\n            }\n\n            var videoSourceKind = HandleVideoSource(StartOptions);\n\n            if (videoSourceKind == null)\n            {\n                WriteLine(\"Video source not set or invalid\");\n\n                return;\n            }\n\n            HandleAudioSource(StartOptions, out var mic, out var speaker);\n\n            HandleWebcam(StartOptions);\n\n            if (StartOptions.FrameRate is int frameRate)\n                _settings.Video.FrameRate = frameRate;\n\n            if (StartOptions.AudioQuality is int aq)\n                _settings.Audio.Quality = aq;\n\n            if (StartOptions.VideoQuality is int vq)\n                _settings.Video.Quality = vq;\n\n            if (StartOptions.Replay is int replayDuration && replayDuration > 0)\n            {\n                _settings.Video.RecorderMode = RecorderMode.Replay;\n                _settings.Video.ReplayDuration = replayDuration;\n            }\n\n            var videoWriter = HandleVideoEncoder(StartOptions, out _);\n\n            if (StartOptions.Delay > 0)\n                Thread.Sleep(StartOptions.Delay);\n\n            if (!_recordingModel.StartRecording(new RecordingModelParams\n            {\n                VideoSourceKind = videoSourceKind,\n                VideoWriter = videoWriter,\n                Microphone = mic,\n                Speaker = speaker\n            }, StartOptions.FileName))\n                return;\n\n            Task.Factory.StartNew(() =>\n            {\n                Loop(StartOptions);\n\n                _recordingModel.StopRecording().Wait();\n\n                Application.Exit();\n            });\n\n            // MouseKeyHook requires a Window Handle to register\n            Application.Run(new ApplicationContext());\n        }\n\n        public void Shot(ShotCmdOptions ShotOptions)\n        {\n            _settings.IncludeCursor = ShotOptions.Cursor;\n\n            // Screenshot Window with Transparency\n            if (Regex.IsMatch(ShotOptions.Source, @\"win:\\d+\"))\n            {\n                var ptr = int.Parse(ShotOptions.Source.Substring(4));\n\n                try\n                {\n                    var win = _platformServices.GetWindow(new IntPtr(ptr));\n                    var bmp = _screenShotModel.ScreenShotWindow(win);\n\n                    _screenShotModel.SaveScreenShot(bmp, ShotOptions.FileName).Wait();\n                }\n                catch\n                {\n                    // Suppress Errors\n                }\n            }\n            else\n            {\n                var videoSourceKind = HandleVideoSource(ShotOptions);\n\n                var bmp = _screenShotModel.GetScreenShot(videoSourceKind).Result;\n\n                _screenShotModel.SaveScreenShot(bmp, ShotOptions.FileName).Wait();\n            }\n        }\n\n        IVideoSourceProvider HandleVideoSource(CommonCmdOptions CommonOptions)\n        {\n            var provider = _videoSourceProviders.FirstOrDefault(M => M.ParseCli(CommonOptions.Source));\n\n            return provider;\n        }\n\n        void HandleAudioSource(StartCmdOptions StartOptions, out IAudioItem Microphone, out IAudioItem Speaker)\n        {\n            Microphone = Speaker = null;\n\n            var mics = _audioSource\n                .Microphones\n                .ToArray();\n\n            var speakers = _audioSource\n                .Speakers\n                .ToArray();\n\n            if (StartOptions.Microphone != -1 && StartOptions.Microphone < mics.Length)\n            {\n                _settings.Audio.RecordMicrophone = true;\n                Microphone = mics[StartOptions.Microphone];\n            }\n\n            if (StartOptions.Speaker != -1 && StartOptions.Speaker < speakers.Length)\n            {\n                _settings.Audio.RecordSpeaker = true;\n                Speaker = speakers[StartOptions.Speaker];\n            }\n        }\n\n        IVideoWriterItem HandleVideoEncoder(StartCmdOptions StartOptions, out IVideoWriterProvider VideoWriterKind)\n        {\n            var selected = _videoWriterProviders\n                .Select(M => new\n                {\n                    kind = M,\n                    writer = M.ParseCli(StartOptions.Encoder)\n                })\n                .FirstOrDefault(M => M.writer != null);\n\n            if (selected != null)\n            {\n                VideoWriterKind = selected.kind;\n\n                return selected.writer;\n            }\n\n            var sharpAviWriterProvider = ServiceProvider.Get<SharpAviWriterProvider>();\n\n            // Steps in video\n            if (StartOptions.Encoder == \"steps:video\")\n            {\n                _settings.Video.RecorderMode = RecorderMode.Steps;\n\n                VideoWriterKind = null;\n                return new StepsVideoWriterItem(sharpAviWriterProvider.First());\n            }\n\n            // Steps in set of images\n            if (StartOptions.Encoder == \"steps:images\")\n            {\n                _settings.Video.RecorderMode = RecorderMode.Steps;\n\n                VideoWriterKind = null;\n                return new ImageFolderWriterItem();\n            }\n\n            VideoWriterKind = sharpAviWriterProvider;\n            return sharpAviWriterProvider.First();\n        }\n\n        void HandleWebcam(StartCmdOptions StartOptions)\n        {\n            if (StartOptions.Webcam != -1 && StartOptions.Webcam < _webcamModel.AvailableCams.Count - 1)\n            {\n                _webcamModel.SelectedCam = _webcamModel.AvailableCams[StartOptions.Webcam + 1];\n\n                // HACK: Sleep to prevent AccessViolationException\n                Thread.Sleep(500);\n            }\n        }\n\n        void Loop(StartCmdOptions StartOptions)\n        {\n            if (StartOptions.Length > 0)\n            {\n                var elapsed = 0;\n\n                Write(TimeSpan.Zero);\n\n                while (elapsed++ < StartOptions.Length)\n                {\n                    Thread.Sleep(1000);\n                    Write(new string('\\b', 8) + TimeSpan.FromSeconds(elapsed));\n                }\n\n                Write(new string('\\b', 8));\n            }\n            else\n            {\n                const string recordingText = \"Press p to pause or resume, q to quit\";\n\n                WriteLine(recordingText);\n\n                char ReadChar()\n                {\n                    if (IsInputRedirected)\n                    {\n                        var line = ReadLine();\n\n                        if (line != null && line.Length == 1)\n                            return line[0];\n\n                        return char.MinValue;\n                    }\n\n                    return char.ToLower(ReadKey(true).KeyChar);\n                }\n\n                char c;\n\n                do\n                {\n                    c = ReadChar();\n\n                    if (c != 'p')\n                        continue;\n\n                    _recordingModel.OnPauseExecute();\n\n                    if (_recordingModel.RecorderState != RecorderState.Paused)\n                    {\n                        WriteLine(\"Resumed\");\n                    }\n                } while (c != 'q');\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Console/FFmpegConsoleManager.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Captura.FFmpeg;\n\nnamespace Captura\n{\n    class FFmpegConsoleManager\n    {\n        readonly FFmpegDownloadModel _downloadModel;\n        readonly FFmpegSettings _ffmpegSettings;\n        readonly object _syncLock = new object();\n\n        public FFmpegConsoleManager(FFmpegDownloadModel DownloadModel,\n            FFmpegSettings FfmpegSettings)\n        {\n            _downloadModel = DownloadModel;\n            _ffmpegSettings = FfmpegSettings;\n        }\n\n        public async Task Run(FFmpegCmdOptions FFmpegOptions)\n        {\n            if (FFmpegOptions.Install != null)\n            {\n                var downloadFolder = FFmpegOptions.Install;\n\n                if (!Directory.Exists(downloadFolder))\n                {\n                    Directory.CreateDirectory(downloadFolder);\n                }\n\n                _ffmpegSettings.FolderPath = downloadFolder;\n\n                var progress = new Progress<FFmpegDownloaderProgress>(FFmpegProgressHandler);\n\n                Console.Write(nameof(FFmpegDownloaderState.Ready));\n\n                var cts = new CancellationTokenSource();\n\n                Console.CancelKeyPress += (S, E) =>\n                {\n                    cts.Cancel();\n\n                    // Prevent abrupt exit\n                    E.Cancel = true;\n                };\n\n                await _downloadModel.Start(progress, cts.Token);\n            }\n        }\n\n        void ClearLastLine()\n        {\n            Console.SetCursorPosition(0, Console.CursorTop);\n            Console.Write(new string(' ', Console.WindowWidth));\n            Console.SetCursorPosition(0, Console.CursorTop - 1);\n        }\n\n        void FFmpegProgressHandler(FFmpegDownloaderProgress DownloaderProgress)\n        {\n            // We don't want to write progress to files\n            if (Console.IsOutputRedirected)\n                return;\n\n            // Locking is necessary to prevent weird output\n            lock (_syncLock)\n            {\n                // Don't use WriteLine() in this block, only Write()\n                ClearLastLine();\n\n                switch (DownloaderProgress.State)\n                {\n                    case FFmpegDownloaderState.Error:\n                        Console.Write(DownloaderProgress.ErrorMessage);\n                        break;\n\n                    case FFmpegDownloaderState.Downloading:\n                        Console.Write($\"{nameof(FFmpegDownloaderState.Downloading)} ({DownloaderProgress.DownloadProgress}%)\");\n                        break;\n\n                    default:\n                        Console.Write(DownloaderProgress.State);\n                        break;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Console/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Captura.Fakes;\nusing Captura.Native;\nusing CommandLine;\nusing static System.Console;\n// ReSharper disable LocalizableElement\n\nnamespace Captura\n{\n    static class Program\n    {\n        [STAThread]\n        static void Main(string[] Args)\n        {\n            User32.SetProcessDPIAware();\n\n            ServiceProvider.LoadModule(new CoreModule());\n            ServiceProvider.LoadModule(new FakesModule());\n            ServiceProvider.LoadModule(new VerbsModule());\n\n            var verbTypes = ServiceProvider\n                .Get<IEnumerable<ICmdlineVerb>>()\n                .Select(M => M.GetType())\n                .ToArray();\n\n            Parser.Default.ParseArguments(Args, verbTypes)\n                .WithParsed((ICmdlineVerb Verb) =>\n                {\n                    // Always display Banner\n                    Banner();\n\n                    Verb.Run();\n                });\n        }\n\n        static void Banner()\n        {\n            var version = ServiceProvider.AppVersion.ToString(3);\n\n            WriteLine($@\"Captura v{version}\n(c) {DateTime.Now.Year} Mathew Sachin\n\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Console/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\n\n[assembly: AssemblyTitle(\"Captura.Console\")]\n[assembly: AssemblyDescription(\"Captures Screen/Window as ScreenShot/ScreenCast along with Audio from Microphone/Loopback, Mouse Cursor, Clicks and Keystrokes\")]\n[assembly: AssemblyCompany(\"Mathew Sachin\")]\n[assembly: AssemblyProduct(\"Captura.Console\")]\n[assembly: AssemblyCopyright(\"(c) 2018 Mathew Sachin\")]\n[assembly: AssemblyTrademark(\"Captura.Console\")]\n[assembly: AssemblyVersion(\"0.0.0\")]\n"
  },
  {
    "path": "src/Captura.Console/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"Captura.Console\": {\n      \"commandName\": \"Project\",\n      \"commandLineArgs\": \"start --encoder mf --replay 20 --speaker 0\"\n    }\n  }\n}"
  },
  {
    "path": "src/Captura.Console/User32.cs",
    "content": "﻿using System.Runtime.InteropServices;\n\n// ReSharper disable InconsistentNaming\nnamespace Captura.Native\n{\n    static class User32\n    {\n        const string DllName = \"user32.dll\";\n\n        [DllImport(DllName)]\n        public static extern bool SetProcessDPIAware();\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/ApiKeys.cs",
    "content": "﻿using System;\nusing Captura.Imgur;\nusing Captura.YouTube;\n\nnamespace Captura\n{\n    /// <summary>\n    /// Holds Api Keys.\n    /// On Development builds, Api Keys are retrieved from User Environment variables.\n    /// On Production builds, AppVeyor embeds Api Keys into the app.\n    /// </summary>\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class ApiKeys : IImgurApiKeys, IYouTubeApiKeys\n    {\n        static string Get(string Key) => Environment.GetEnvironmentVariable(Key, EnvironmentVariableTarget.User) ?? \"\";\n\n        public string ImgurClientId => Get(\"imgur_client_id\");\n\n        public string ImgurSecret => Get(\"imgur_secret\");\n\n        public string YouTubeClientId => Get(\"yt_client_id\");\n\n        public string YouTubeClientSecret => Get(\"yt_client_secret\");\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/Captura.Core.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net472</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n    <ProjectReference Include=\"..\\Captura.FFmpeg\\Captura.FFmpeg.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Hotkeys\\Captura.Hotkeys.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Imgur\\Captura.Imgur.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Loc\\Captura.Loc.csproj\" />\n    <ProjectReference Include=\"..\\Captura.MouseKeyHook\\Captura.MouseKeyHook.csproj\" />\n    <ProjectReference Include=\"..\\Captura.NAudio\\Captura.NAudio.csproj\" />\n    <ProjectReference Include=\"..\\Captura.SharpAvi\\Captura.SharpAvi.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Windows\\Captura.Windows.csproj\" />\n    <ProjectReference Include=\"..\\Captura.YouTube\\Captura.YouTube.csproj\" />\n    <ProjectReference Include=\"..\\Screna\\Screna.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"11.0.2\" />\n    <PackageReference Include=\"ReactiveProperty\" Version=\"6.1.3\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Captura.Core/CoreModule.cs",
    "content": "﻿using Captura.Models;\nusing Captura.Audio;\nusing Captura.FFmpeg;\nusing Captura.Hotkeys;\nusing Captura.Imgur;\nusing Captura.Loc;\nusing Captura.MouseKeyHook;\nusing Captura.SharpAvi;\nusing Captura.Video;\nusing Captura.ViewModels;\nusing Captura.Webcam;\nusing Captura.Windows;\nusing Captura.YouTube;\n\nnamespace Captura\n{\n    public class CoreModule : IModule\n    {\n        public void OnLoad(IBinder Binder)\n        {\n            Binder.Bind<IAudioWriterItem, WaveItem>();\n\n            WindowsModule.Load(Binder);\n\n            FFmpegModule.Load(Binder);\n\n            BindViewModels(Binder);\n            BindSettings(Binder);\n            BindImageWriters(Binder);\n            BindVideoWriterProviders(Binder);\n            BindVideoSourceProviders(Binder);\n            BindAudioSource(Binder);\n            BindUpdateChecker(Binder);\n\n            // Recent\n            Binder.Bind<IRecentList, RecentListRepository>();\n            Binder.Bind<IRecentItemSerializer, FileRecentSerializer>();\n            Binder.Bind<IRecentItemSerializer, UploadRecentSerializer>();\n\n            Binder.Bind<IImageUploader, ImgurUploader>();\n            Binder.Bind<IIconSet, MaterialDesignIcons>();\n            Binder.Bind<IImgurApiKeys, ApiKeys>();\n            Binder.Bind<IYouTubeApiKeys, ApiKeys>();\n\n            Binder.BindSingleton<HotKeyManager>();\n\n            Binder.Bind<ILocalizationProvider>(() => LanguageManager.Instance);\n\n            Binder.Bind<IFpsManager, FpsManager>();\n        }\n\n        public void Dispose()\n        {\n            WindowsModule.Unload();\n        }\n\n        static void BindImageWriters(IBinder Binder)\n        {\n            Binder.BindAsInterfaceAndClass<IImageWriterItem, DiskWriter>();\n            Binder.BindAsInterfaceAndClass<IImageWriterItem, ClipboardWriter>();\n            Binder.BindAsInterfaceAndClass<IImageWriterItem, ImageUploadWriter>();\n            Binder.BindAsInterfaceAndClass<IImageWriterItem, EditorWriter>();\n        }\n\n        static void BindViewModels(IBinder Binder)\n        {\n            Binder.BindSingleton<TimerModel>();\n            Binder.BindSingleton<ScreenShotModel>();\n            Binder.BindSingleton<RecordingModel>();\n            Binder.BindSingleton<WebcamModel>();\n            Binder.BindSingleton<KeymapViewModel>();\n        }\n\n        static void BindUpdateChecker(IBinder Binder)\n        {\n            var version = ServiceProvider.AppVersion;\n\n            if (version?.Major == 0)\n            {\n                Binder.Bind<IUpdateChecker, DevUpdateChecker>();\n            }\n            else Binder.Bind<IUpdateChecker, UpdateChecker>();\n        }\n\n        static void BindAudioSource(IBinder Binder)\n        {\n            Binder.Bind<IAudioSource, NAudioSource>();\n        }\n\n        static void BindVideoSourceProviders(IBinder Binder)\n        {\n            Binder.BindAsInterfaceAndClass<IVideoSourceProvider, NoVideoSourceProvider>();\n            Binder.BindAsInterfaceAndClass<IVideoSourceProvider, AroundMouseSourceProvider>();\n            Binder.BindAsInterfaceAndClass<IVideoSourceProvider, WebcamSourceProvider>();\n            Binder.BindAsInterfaceAndClass<IVideoSourceProvider, FullScreenSourceProvider>();\n            Binder.BindAsInterfaceAndClass<IVideoSourceProvider, ScreenSourceProvider>();\n            Binder.BindAsInterfaceAndClass<IVideoSourceProvider, WindowSourceProvider>();\n            Binder.BindAsInterfaceAndClass<IVideoSourceProvider, RegionSourceProvider>();\n        }\n\n        static void BindVideoWriterProviders(IBinder Binder)\n        {\n            Binder.BindAsInterfaceAndClass<IVideoWriterProvider, SharpAviWriterProvider>();\n            Binder.BindAsInterfaceAndClass<IVideoWriterProvider, DiscardWriterProvider>();\n        }\n\n        static void BindSettings(IBinder Binder)\n        {\n            Binder.BindSingleton<Settings>();\n            Binder.Bind(() => Binder.Get<Settings>().Audio);\n            Binder.Bind(() => Binder.Get<Settings>().Proxy);\n            Binder.Bind(() => Binder.Get<Settings>().Sounds);\n            Binder.Bind(() => Binder.Get<Settings>().Imgur);\n            Binder.Bind(() => Binder.Get<Settings>().Steps);\n            Binder.Bind(() => Binder.Get<Settings>().Video);\n            Binder.Bind(() => Binder.Get<Settings>().UI);\n            Binder.Bind(() => Binder.Get<Settings>().WebcamOverlay);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Extensions.cs",
    "content": "﻿using System;\nusing DSize = System.Drawing.Size;\nusing WSize = System.Windows.Size;\nusing System.Threading.Tasks;\nusing System.Windows.Input;\nusing Captura.Loc;\nusing Captura.Models;\n\nnamespace Captura\n{\n    public static class Extensions\n    {\n        public static void ExecuteIfCan(this ICommand Command)\n        {\n            if (Command.CanExecute(null))\n                Command.Execute(null);\n        }\n\n        public static async Task UploadImage(this IBitmapImage Bitmap)\n        {\n            var uploadWriter = ServiceProvider.Get<ImageUploadWriter>();\n\n            var settings = ServiceProvider.Get<Settings>();\n\n            var response = await uploadWriter.Save(Bitmap, settings.ScreenShots.ImageFormat);\n\n            switch (response)\n            {\n                case Exception ex:\n                    var loc = ServiceProvider.Get<ILocalizationProvider>();\n                    ServiceProvider.MessageProvider.ShowException(ex, loc.ImageUploadFailed);\n                    break;\n\n                case UploadResult uploadResult:\n                    uploadResult.Url.WriteToClipboard();\n                    break;\n            }\n        }\n\n        public static DSize ToDrawingSize(this WSize Size)\n        {\n            return new DSize((int)Math.Round(Size.Width), (int)Math.Round(Size.Height));\n        }\n\n        public static WSize ToWpfSize(this DSize Size)\n        {\n            return new WSize(Size.Width, Size.Height);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/FpsManager.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace Captura.Models\n{\n    public class FpsManager : NotifyPropertyChanged, IFpsManager\n    {\n        readonly Stopwatch _sw = new Stopwatch();\n        readonly TimeSpan _diff = TimeSpan.FromSeconds(1);\n        long _frames;\n        int _fps;\n\n        public void OnFrame()\n        {\n            if (!_sw.IsRunning)\n            {\n                _sw.Start();\n                Fps = 0;\n\n                return;\n            }\n\n            ++_frames;\n\n            if (_sw.Elapsed < _diff) \n                return;\n\n            Fps = (int)Math.Round(_frames / _sw.Elapsed.TotalSeconds);\n            _frames = 0;\n\n            _sw.Restart();\n        }\n\n        public int Fps\n        {\n            get => _fps;\n            private set => Set(ref _fps, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/MaterialDesignIcons.cs",
    "content": "﻿// ReSharper disable UnusedMember.Global\nnamespace Captura\n{\n    public class MaterialDesignIcons : IIconSet\n    {\n        public string Add { get; } = \"M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z\";\n\n        public string Arrow { get; } = \"M5,17.59L15.59,7H9V5H19V15H17V8.41L6.41,19L5,17.59Z\";\n\n        public string Back { get; } = \"M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z\";\n\n        public string Border { get; } = \"M3,21V3H21V21H3M5,5V19H19V5H5Z\";\n\n        public string Brightness { get; } = \"M12,18V6A6,6 0 0,1 18,12A6,6 0 0,1 12,18M20,15.31L23.31,12L20,8.69V4H15.31L12,0.69L8.69,4H4V8.69L0.69,12L4,15.31V20H8.69L12,23.31L15.31,20H20V15.31Z\";\n\n        public string Brush { get; } = \"M20.71,4.63L19.37,3.29C19,2.9 18.35,2.9 17.96,3.29L9,12.25L11.75,15L20.71,6.04C21.1,5.65 21.1,5 20.71,4.63M7,14A3,3 0 0,0 4,17C4,18.31 2.84,19 2,19C2.92,20.22 4.5,21 6,21A4,4 0 0,0 10,17A3,3 0 0,0 7,14Z\";\n\n        public string Camera { get; } = \"M4,4H7L9,2H15L17,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4M12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17A5,5 0 0,0 17,12A5,5 0 0,0 12,7M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9Z\";\n\n        public string Check { get; } = \"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\";\n\n        public string ClearNotifications { get; } = \"M5,13H19V11H5M3,17H17V15H3M7,7V9H21V7\";\n\n        public string Clipboard { get; } = \"M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M7,7H17V5H19V19H5V5H7V7Z\";\n\n        public string Close { get; } = \"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\";\n\n        public string Code { get; } = \"M14.6,16.6L19.2,12L14.6,7.4L16,6L22,12L16,18L14.6,16.6M9.4,16.6L4.8,12L9.4,7.4L8,6L2,12L8,18L9.4,16.6Z\";\n\n        public string Collapse { get; } = \"M19.5,3.09L15,7.59V4H13V11H20V9H16.41L20.91,4.5L19.5,3.09M4,13V15H7.59L3.09,19.5L4.5,20.91L9,16.41V20H11V13H4Z\";\n\n        public string Contrast { get; } = \"M12,20C9.79,20 7.79,19.1 6.34,17.66L17.66,6.34C19.1,7.79 20,9.79 20,12A8,8 0 0,1 12,20M6,8H8V6H9.5V8H11.5V9.5H9.5V11.5H8V9.5H6M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,16H17V14.5H12V16Z\";\n\n        public string Crop { get; } = \"M7,17V1H5V5H1V7H5V17A2,2 0 0,0 7,19H17V23H19V19H23V17M17,15H19V7C19,5.89 18.1,5 17,5H9V7H17V15Z\";\n\n        public string Cursor { get; } = \"M10.07,14.27C10.57,14.03 11.16,14.25 11.4,14.75L13.7,19.74L15.5,18.89L13.19,13.91C12.95,13.41 13.17,12.81 13.67,12.58L13.95,12.5L16.25,12.05L8,5.12V15.9L9.82,14.43L10.07,14.27M13.64,21.97C13.14,22.21 12.54,22 12.31,21.5L10.13,16.76L7.62,18.78C7.45,18.92 7.24,19 7,19A1,1 0 0,1 6,18V3A1,1 0 0,1 7,2C7.24,2 7.47,2.09 7.64,2.23L7.65,2.22L19.14,11.86C19.57,12.22 19.62,12.85 19.27,13.27C19.12,13.45 18.91,13.57 18.7,13.61L15.54,14.23L17.74,18.96C18,19.46 17.76,20.05 17.26,20.28L13.64,21.97Z\";\n\n        public string Delete { get; } = \"M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z\";\n\n        public string Dollar { get; } = \"M7,15H9C9,16.08 10.37,17 12,17C13.63,17 15,16.08 15,15C15,13.9 13.96,13.5 11.76,12.97C9.64,12.44 7,11.78 7,9C7,7.21 8.47,5.69 10.5,5.18V3H13.5V5.18C15.53,5.69 17,7.21 17,9H15C15,7.92 13.63,7 12,7C10.37,7 9,7.92 9,9C9,10.1 10.04,10.5 12.24,11.03C14.36,11.56 17,12.22 17,15C17,16.79 15.53,18.31 13.5,18.82V21H10.5V18.82C8.47,18.31 7,16.79 7,15Z\";\n\n        public string DoubleDown { get; } = \"M16.59,5.59L18,7L12,13L6,7L7.41,5.59L12,10.17L16.59,5.59M16.59,11.59L18,13L12,19L6,13L7.41,11.59L12,16.17L16.59,11.59Z\";\n\n        public string Download { get; } = \"M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z\";\n\n        public string Ellipse { get; } = \"M23,9V15H20.35C19.38,17.12 17.43,18.78 15,19.54V22H9V19.54C5.5,18.45 3,15.5 3,12C3,7.58 7.03,4 12,4C15.78,4 19,6.07 20.35,9H23M17,15V9H18.06C16.85,7.21 14.59,6 12,6C8.13,6 5,8.69 5,12C5,14.39 6.64,16.46 9,17.42V16H15V17.42C16.29,16.9 17.35,16.05 18.06,15H17M19,13H21V11H19V13M11,20H13V18H11V20Z\";\n\n        public string Eraser { get; } = \"M16.24,3.56L21.19,8.5C21.97,9.29 21.97,10.55 21.19,11.34L12,20.53C10.44,22.09 7.91,22.09 6.34,20.53L2.81,17C2.03,16.21 2.03,14.95 2.81,14.16L13.41,3.56C14.2,2.78 15.46,2.78 16.24,3.56M4.22,15.58L7.76,19.11C8.54,19.9 9.8,19.9 10.59,19.11L14.12,15.58L9.17,10.63L4.22,15.58Z\";\n\n        public string Error { get; } = \"M11,15H13V17H11V15M11,7H13V13H11V7M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20Z\";\n\n        public string Expand { get; } = \"M10,21V19H6.41L10.91,14.5L9.5,13.09L5,17.59V14H3V21H10M14.5,10.91L19,6.41V10H21V3H14V5H17.59L13.09,9.5L14.5,10.91Z\";\n\n        public string Expander { get; } = \"M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M7,10L12,15L17,10H7Z\";\n\n        public string Folder { get; } = \"M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z\";\n\n        public string Font { get; } = \"M9.62,12L12,5.67L14.37,12M11,3L5.5,17H7.75L8.87,14H15.12L16.25,17H18.5L13,3H11Z\";\n\n        public string Forward { get; } = \"M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z\";\n\n        public string Game { get; } = \"M7,6H17A6,6 0 0,1 23,12A6,6 0 0,1 17,18C15.22,18 13.63,17.23 12.53,16H11.47C10.37,17.23 8.78,18 7,18A6,6 0 0,1 1,12A6,6 0 0,1 7,6M6,9V11H4V13H6V15H8V13H10V11H8V9H6M15.5,12A1.5,1.5 0 0,0 14,13.5A1.5,1.5 0 0,0 15.5,15A1.5,1.5 0 0,0 17,13.5A1.5,1.5 0 0,0 15.5,12M18.5,9A1.5,1.5 0 0,0 17,10.5A1.5,1.5 0 0,0 18.5,12A1.5,1.5 0 0,0 20,10.5A1.5,1.5 0 0,0 18.5,9Z\";\n\n        public string GitHub { get; } = \"M12,2A10,10 0 0,0 2,12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0 0,0 12,2Z\";\n\n        public string Hand { get; } = \"M10,2A2,2 0 0,1 12,4V8.5C12,8.5 14,8.25 14,9.25C14,9.25 16,9 16,10C16,10 18,9.75 18,10.75C18,10.75 20,10.5 20,11.5V15C20,16 17,21 17,22H9C9,22 7,15 4,13C4,13 3,7 8,12V4A2,2 0 0,1 10,2Z\";\n\n        public string Help { get; } = \"M10,19H13V22H10V19M12,2C17.35,2.22 19.68,7.62 16.5,11.67C15.67,12.67 14.33,13.33 13.67,14.17C13,15 13,16 13,17H10C10,15.33 10,13.92 10.67,12.92C11.33,11.92 12.67,11.33 13.5,10.67C15.92,8.43 15.32,5.26 12,5A3,3 0 0,0 9,8H6A6,6 0 0,1 12,2Z\";\n\n        public string History { get; } = \"M13.5,8H12V13L16.28,15.54L17,14.33L13.5,12.25V8M13,3A9,9 0 0,0 4,12H1L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3\";\n\n        public string Home { get; } = \"M19.07,4.93C17.22,3 14.66,1.96 12,2C9.34,1.96 6.79,3 4.94,4.93C3,6.78 1.96,9.34 2,12C1.96,14.66 3,17.21 4.93,19.06C6.78,21 9.34,22.04 12,22C14.66,22.04 17.21,21 19.06,19.07C21,17.22 22.04,14.66 22,12C22.04,9.34 21,6.78 19.07,4.93M17,12V18H13.5V13H10.5V18H7V12H5L12,5L19.5,12H17Z\";\n\n        public string Image { get; } = \"M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z\";\n\n        public string Keyboard { get; } = \"M6,16H18V18H6V16M6,13V15H2V13H6M7,15V13H10V15H7M11,15V13H13V15H11M14,15V13H17V15H14M18,15V13H22V15H18M2,10H5V12H2V10M19,12V10H22V12H19M18,12H16V10H18V12M8,12H6V10H8V12M12,12H9V10H12V12M15,12H13V10H15V12M2,9V7H4V9H2M5,9V7H7V9H5M8,9V7H10V9H8M11,9V7H13V9H11M14,9V7H16V9H14M17,9V7H22V9H17Z\";\n\n        public string Line { get; } = \"M15,3V7.59L7.59,15H3V21H9V16.42L16.42,9H21V3M17,5H19V7H17M5,17H7V19H5\";\n\n        public string Link { get; } = \"M16,6H13V7.9H16C18.26,7.9 20.1,9.73 20.1,12A4.1,4.1 0 0,1 16,16.1H13V18H16A6,6 0 0,0 22,12C22,8.68 19.31,6 16,6M3.9,12C3.9,9.73 5.74,7.9 8,7.9H11V6H8A6,6 0 0,0 2,12A6,6 0 0,0 8,18H11V16.1H8C5.74,16.1 3.9,14.26 3.9,12M8,13H16V11H8V13Z\";\n\n        public string Mic { get; } = \"M12,2A3,3 0 0,1 15,5V11A3,3 0 0,1 12,14A3,3 0 0,1 9,11V5A3,3 0 0,1 12,2M19,11C19,14.53 16.39,17.44 13,17.93V21H11V17.93C7.61,17.44 5,14.53 5,11H7A5,5 0 0,0 12,16A5,5 0 0,0 17,11H19Z\";\n\n        public string Minimize { get; } = \"M19,13H5V11H19V13Z\";\n\n        public string Minus { get; } = \"M19,13H5V11H19V13Z\";\n\n        public string More { get; } = \"M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z\";\n\n        public string MultipleMonitor { get; } = \"M22,17V7H6V17H22M22,5A2,2 0 0,1 24,7V17C24,18.11 23.1,19 22,19H16V21H18V23H10V21H12V19H6C4.89,19 4,18.11 4,17V7A2,2 0 0,1 6,5H22M2,3V15H0V3A2,2 0 0,1 2,1H20V3H2Z\";\n\n        public string NewFile { get; } = \"M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11,4H6V20H11L18,20V11H11V4Z\";\n\n        public string NoVideo { get; } = \"M3.27,2L2,3.27L4.73,6H4A1,1 0 0,0 3,7V17A1,1 0 0,0 4,18H16C16.2,18 16.39,17.92 16.54,17.82L19.73,21L21,19.73M21,6.5L17,10.5V7A1,1 0 0,0 16,6H9.82L21,17.18V6.5Z\";\n\n        public string Opacity { get; } = \"M17.66,8L12,2.35L6.34,8C4.78,9.56 4,11.64 4,13.64C4,15.64 4.78,17.75 6.34,19.31C7.9,20.87 9.95,21.66 12,21.66C14.05,21.66 16.1,20.87 17.66,19.31C19.22,17.75 20,15.64 20,13.64C20,11.64 19.22,9.56 17.66,8M6,14C6,12 6.62,10.73 7.76,9.6L12,5.27L16.24,9.65C17.38,10.77 18,12 18,14H6Z\";\n\n        public string OpenFile { get; } = \"M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z\";\n\n        public string Music { get; } = \"M12,3V12.26C11.5,12.09 11,12 10.5,12C8,12 6,14 6,16.5C6,19 8,21 10.5,21C13,21 15,19 15,16.5V6H19V3H12Z\";\n\n        public string Pause { get; } = \"M14,19H18V5H14M6,19H10V5H6V19Z\";\n\n        public string PayPal { get; } = \"M8.32,21.97C8.21,21.92 8.08,21.76 8.06,21.65C8.03,21.5 8,21.76 8.66,17.56C9.26,13.76 9.25,13.82 9.33,13.71C9.46,13.54 9.44,13.54 10.94,13.53C12.26,13.5 12.54,13.5 13.13,13.41C16.38,12.96 18.39,11.05 19.09,7.75C19.13,7.53 19.17,7.34 19.18,7.34C19.18,7.33 19.25,7.38 19.33,7.44C20.36,8.22 20.71,9.66 20.32,11.58C19.86,13.87 18.64,15.39 16.74,16.04C15.93,16.32 15.25,16.43 14.05,16.46C13.25,16.5 13.23,16.5 13,16.65C12.83,16.82 12.84,16.79 12.45,19.2C12.18,20.9 12.08,21.45 12.04,21.55C11.97,21.71 11.83,21.85 11.67,21.93L11.56,22H10C8.71,22 8.38,22 8.32,21.97V21.97M3.82,19.74C3.63,19.64 3.5,19.47 3.5,19.27C3.5,19 6.11,2.68 6.18,2.5C6.27,2.32 6.5,2.13 6.68,2.06L6.83,2H10.36C14.27,2 14.12,2 15,2.2C17.62,2.75 18.82,4.5 18.37,7.13C17.87,10.06 16.39,11.8 13.87,12.43C13,12.64 12.39,12.7 10.73,12.7C9.42,12.7 9.32,12.71 9.06,12.85C8.8,13 8.59,13.27 8.5,13.6C8.46,13.67 8.23,15.07 7.97,16.7C7.71,18.33 7.5,19.69 7.5,19.72L7.47,19.78H5.69C4.11,19.78 3.89,19.78 3.82,19.74V19.74Z\";\n\n        public string Pencil { get; } = \"M16.84,2.73C16.45,2.73 16.07,2.88 15.77,3.17L13.65,5.29L18.95,10.6L21.07,8.5C21.67,7.89 21.67,6.94 21.07,6.36L17.9,3.17C17.6,2.88 17.22,2.73 16.84,2.73M12.94,6L4.84,14.11L7.4,14.39L7.58,16.68L9.86,16.85L10.15,19.41L18.25,11.3M4.25,15.04L2.5,21.73L9.2,19.94L8.96,17.78L6.65,17.61L6.47,15.29\";\n\n        public string Play { get; } = \"M8,5.14V19.14L19,12.14L8,5.14Z\";\n\n        public string Plus { get; } = \"M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z\";\n\n        public string Record { get; } = \"M19,12C19,15.86 15.86,19 12,19C8.14,19 5,15.86 5,12C5,8.14 8.14,5 12,5C15.86,5 19,8.14 19,12Z\";\n\n        public string Rectangle { get; } = \"M2,4H8V6H16V4H22V10H20V14H22V20H16V18H8V20H2V14H4V10H2V4M16,10V8H8V10H6V14H8V16H16V14H18V10H16M4,6V8H6V6H4M18,6V8H20V6H18M4,16V18H6V16H4M18,16V18H20V16H18Z\";\n\n        public string Redo { get; } = \"M10.5,7A6.5,6.5 0 0,0 4,13.5A6.5,6.5 0 0,0 10.5,20H14V18H10.5C8,18 6,16 6,13.5C6,11 8,9 10.5,9H16.17L13.09,12.09L14.5,13.5L20,8L14.5,2.5L13.08,3.91L16.17,7H10.5M18,18H16V20H18V18Z\";\n\n        public string Refresh { get; } = \"M12,18A6,6 0 0,1 6,12C6,11 6.25,10.03 6.7,9.2L5.24,7.74C4.46,8.97 4,10.43 4,12A8,8 0 0,0 12,20V23L16,19L12,15M12,4V1L8,5L12,9V6A6,6 0 0,1 18,12C18,13 17.75,13.97 17.3,14.8L18.76,16.26C19.54,15.03 20,13.57 20,12A8,8 0 0,0 12,4Z\";\n\n        public string Region { get; } = \"M19,3H15V5H19V9H21V5C21,3.89 20.1,3 19,3M19,19H15V21H19A2,2 0 0,0 21,19V15H19M5,15H3V19A2,2 0 0,0 5,21H9V19H5M3,5V9H5V5H9V3H5A2,2 0 0,0 3,5Z\";\n\n        public string Restore { get; } = \"M13,3A9,9 0 0,0 4,12H1L4.89,15.89L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3Z\";\n\n        public string RotateLeft { get; } = \"M13,4.07V1L8.45,5.55L13,10V6.09C15.84,6.57 18,9.03 18,12C18,14.97 15.84,17.43 13,17.91V19.93C16.95,19.44 20,16.08 20,12C20,7.92 16.95,4.56 13,4.07M7.1,18.32C8.26,19.22 9.61,19.76 11,19.93V17.9C10.13,17.75 9.29,17.41 8.54,16.87L7.1,18.32M6.09,13H4.07C4.24,14.39 4.79,15.73 5.69,16.89L7.1,15.47C6.58,14.72 6.23,13.88 6.09,13M7.11,8.53L5.7,7.11C4.8,8.27 4.24,9.61 4.07,11H6.09C6.23,10.13 6.58,9.28 7.11,8.53Z\";\n\n        public string RotateRight { get; } = \"M16.89,15.5L18.31,16.89C19.21,15.73 19.76,14.39 19.93,13H17.91C17.77,13.87 17.43,14.72 16.89,15.5M13,17.9V19.92C14.39,19.75 15.74,19.21 16.9,18.31L15.46,16.87C14.71,17.41 13.87,17.76 13,17.9M19.93,11C19.76,9.61 19.21,8.27 18.31,7.11L16.89,8.53C17.43,9.28 17.77,10.13 17.91,11M15.55,5.55L11,1V4.07C7.06,4.56 4,7.92 4,12C4,16.08 7.05,19.44 11,19.93V17.91C8.16,17.43 6,14.97 6,12C6,9.03 8.16,6.57 11,6.09V10L15.55,5.55Z\";\n\n        public string RoundCorner { get; } = \"M19,19H21V21H19V19M19,17H21V15H19V17M3,13H5V11H3V13M3,17H5V15H3V17M3,9H5V7H3V9M3,5H5V3H3V5M7,5H9V3H7V5M15,21H17V19H15V21M11,21H13V19H11V21M15,21H17V19H15V21M7,21H9V19H7V21M3,21H5V19H3V21M21,8A5,5 0 0,0 16,3H11V5H16A3,3 0 0,1 19,8V13H21V8Z\";\n\n        public string Save { get; } = \"M15,5V9H5V19H9.35C8.5,18.27 8,17.19 8,16A4,4 0 0,1 12,12A4,4 0 0,1 16,16C16,17.19 15.5,18.27 14.65,19H19V7.83L16.17,5H15M5,7H13V5H5V7M17,3L21,7V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5A2,2 0 0,1 5,3H17M12,14A2,2 0 0,0 10,16A2,2 0 0,0 12,18A2,2 0 0,0 14,16A2,2 0 0,0 12,14Z\";\n\n        public string Screen { get; } = \"M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z\";\n\n        public string Select { get; } = \"M4,3H5V5H3V4A1,1 0 0,1 4,3M20,3A1,1 0 0,1 21,4V5H19V3H20M15,5V3H17V5H15M11,5V3H13V5H11M7,5V3H9V5H7M21,20A1,1 0 0,1 20,21H19V19H21V20M15,21V19H17V21H15M11,21V19H13V21H11M7,21V19H9V21H7M4,21A1,1 0 0,1 3,20V19H5V21H4M3,15H5V17H3V15M21,15V17H19V15H21M3,11H5V13H3V11M21,11V13H19V11H21M3,7H5V9H3V7M21,7V9H19V7H21Z\";\n\n        public string Settings { get; } = \"M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z\";\n\n        public string SnapToWindow { get; } = \"M11,2V4.07C7.38,4.53 4.53,7.38 4.07,11H2V13H4.07C4.53,16.62 7.38,19.47 11,19.93V22H13V19.93C16.62,19.47 19.47,16.62 19.93,13H22V11H19.93C19.47,7.38 16.62,4.53 13,4.07V2M11,6.08V8H13V6.09C15.5,6.5 17.5,8.5 17.92,11H16V13H17.91C17.5,15.5 15.5,17.5 13,17.92V16H11V17.91C8.5,17.5 6.5,15.5 6.08,13H8V11H6.09C6.5,8.5 8.5,6.5 11,6.08M12,11A1,1 0 0,0 11,12A1,1 0 0,0 12,13A1,1 0 0,0 13,12A1,1 0 0,0 12,11Z\";\n\n        public string Speaker { get; } = \"M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z\";\n\n        public string Stop { get; } = \"M18,18H6V6H18V18Z\";\n\n        public string StrokeEraser { get; } = \"M15.14,3C14.63,3 14.12,3.2 13.73,3.59L2.59,14.73C1.81,15.5 1.81,16.77 2.59,17.56L5.03,20H12.69L21.41,11.27C22.2,10.5 22.2,9.23 21.41,8.44L16.56,3.59C16.17,3.2 15.65,3 15.14,3M17,18L15,20H22V18\";\n\n        public string Undo { get; } = \"M13.5,7A6.5,6.5 0 0,1 20,13.5A6.5,6.5 0 0,1 13.5,20H10V18H13.5C16,18 18,16 18,13.5C18,11 16,9 13.5,9H7.83L10.91,12.09L9.5,13.5L4,8L9.5,2.5L10.92,3.91L7.83,7H13.5M6,18H8V20H6V18Z\";\n\n        public string Timer { get; } = \"M12,20A7,7 0 0,1 5,13A7,7 0 0,1 12,6A7,7 0 0,1 19,13A7,7 0 0,1 12,20M19.03,7.39L20.45,5.97C20,5.46 19.55,5 19.04,4.56L17.62,6C16.07,4.74 14.12,4 12,4A9,9 0 0,0 3,13A9,9 0 0,0 12,22C17,22 21,17.97 21,13C21,10.88 20.26,8.93 19.03,7.39M11,14H13V8H11M15,1H9V3H15V1Z\";\n\n        public string Translate { get; } = \"M12.87,15.07L10.33,12.56L10.36,12.53C12.1,10.59 13.34,8.36 14.07,6H17V4H10V2H8V4H1V6H12.17C11.5,7.92 10.44,9.75 9,11.35C8.07,10.32 7.3,9.19 6.69,8H4.69C5.42,9.63 6.42,11.17 7.67,12.56L2.58,17.58L4,19L9,14L12.11,17.11L12.87,15.07M18.5,10H16.5L12,22H14L15.12,19H19.87L21,22H23L18.5,10M15.88,17L17.5,12.67L19.12,17H15.88Z\";\n\n        public string Trim { get; } = \"M9,11H15V8L19,12L15,16V13H9V16L5,12L9,8V11M2,20V4H4V20H2M20,20V4H22V20H20Z\";\n\n        public string Twitch { get; } = \"M4,2H22V14L17,19H13L10,22H7V19H2V6L4,2M20,13V4H6V16H9V19L12,16H17L20,13M15,7H17V12H15V7M12,7V12H10V7H12Z\";\n\n        public string Upload { get; } = \"M9,16V10H5L12,3L19,10H15V16H9M5,20V18H19V20H5Z\";\n\n        public string Video { get; } = \"M17,10.5V7A1,1 0 0,0 16,6H4A1,1 0 0,0 3,7V17A1,1 0 0,0 4,18H16A1,1 0 0,0 17,17V13.5L21,17.5V6.5L17,10.5Z\";\n\n        public string VideoFile { get; } = \"M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M17,19V13L14,15.2V13H7V19H14V16.8L17,19Z\";\n\n        public string Visibility { get; } = \"M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17M12,4.5C7,4.5 2.73,7.61 1,12C2.73,16.39 7,19.5 12,19.5C17,19.5 21.27,16.39 23,12C21.27,7.61 17,4.5 12,4.5Z\";\n\n        public string VisibilityHide { get; } = \"M11.83,9L15,12.16C15,12.11 15,12.05 15,12A3,3 0 0,0 12,9C11.94,9 11.89,9 11.83,9M7.53,9.8L9.08,11.35C9.03,11.56 9,11.77 9,12A3,3 0 0,0 12,15C12.22,15 12.44,14.97 12.65,14.92L14.2,16.47C13.53,16.8 12.79,17 12,17A5,5 0 0,1 7,12C7,11.21 7.2,10.47 7.53,9.8M2,4.27L4.28,6.55L4.73,7C3.08,8.3 1.78,10 1,12C2.73,16.39 7,19.5 12,19.5C13.55,19.5 15.03,19.2 16.38,18.66L16.81,19.08L19.73,22L21,20.73L3.27,3M12,7A5,5 0 0,1 17,12C17,12.64 16.87,13.26 16.64,13.82L19.57,16.75C21.07,15.5 22.27,13.86 23,12C21.27,7.61 17,4.5 12,4.5C10.6,4.5 9.26,4.75 8,5.2L10.17,7.35C10.74,7.13 11.35,7 12,7Z\";\n\n        public string Web { get; } = \"M16.36,14C16.44,13.34 16.5,12.68 16.5,12C16.5,11.32 16.44,10.66 16.36,10H19.74C19.9,10.64 20,11.31 20,12C20,12.69 19.9,13.36 19.74,14M14.59,19.56C15.19,18.45 15.65,17.25 15.97,16H18.92C17.96,17.65 16.43,18.93 14.59,19.56M14.34,14H9.66C9.56,13.34 9.5,12.68 9.5,12C9.5,11.32 9.56,10.65 9.66,10H14.34C14.43,10.65 14.5,11.32 14.5,12C14.5,12.68 14.43,13.34 14.34,14M12,19.96C11.17,18.76 10.5,17.43 10.09,16H13.91C13.5,17.43 12.83,18.76 12,19.96M8,8H5.08C6.03,6.34 7.57,5.06 9.4,4.44C8.8,5.55 8.35,6.75 8,8M5.08,16H8C8.35,17.25 8.8,18.45 9.4,19.56C7.57,18.93 6.03,17.65 5.08,16M4.26,14C4.1,13.36 4,12.69 4,12C4,11.31 4.1,10.64 4.26,10H7.64C7.56,10.66 7.5,11.32 7.5,12C7.5,12.68 7.56,13.34 7.64,14M12,4.03C12.83,5.23 13.5,6.57 13.91,8H10.09C10.5,6.57 11.17,5.23 12,4.03M18.92,8H15.97C15.65,6.75 15.19,5.55 14.59,4.44C16.43,5.07 17.96,6.34 18.92,8M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z\";\n\n        public string Webcam { get; } = \"M12,2A7,7 0 0,1 19,9A7,7 0 0,1 12,16A7,7 0 0,1 5,9A7,7 0 0,1 12,2M12,4A5,5 0 0,0 7,9A5,5 0 0,0 12,14A5,5 0 0,0 17,9A5,5 0 0,0 12,4M12,6A3,3 0 0,1 15,9A3,3 0 0,1 12,12A3,3 0 0,1 9,9A3,3 0 0,1 12,6M6,22A2,2 0 0,1 4,20C4,19.62 4.1,19.27 4.29,18.97L6.11,15.81C7.69,17.17 9.75,18 12,18C14.25,18 16.31,17.17 17.89,15.81L19.71,18.97C19.9,19.27 20,19.62 20,20A2,2 0 0,1 18,22H6Z\";\n\n        public string Window { get; } = \"M4,4H20V20H4V4M6,8V18H18V8H6Z\";\n\n        public string YouTube { get; } = \"M10,15L15.19,12L10,9V15M21.56,7.17C21.69,7.64 21.78,8.27 21.84,9.07C21.91,9.87 21.94,10.56 21.94,11.16L22,12C22,14.19 21.84,15.8 21.56,16.83C21.31,17.73 20.73,18.31 19.83,18.56C19.36,18.69 18.5,18.78 17.18,18.84C15.88,18.91 14.69,18.94 13.59,18.94L12,19C7.81,19 5.2,18.84 4.17,18.56C3.27,18.31 2.69,17.73 2.44,16.83C2.31,16.36 2.22,15.73 2.16,14.93C2.09,14.13 2.06,13.44 2.06,12.84L2,12C2,9.81 2.16,8.2 2.44,7.17C2.69,6.27 3.27,5.69 4.17,5.44C4.64,5.31 5.5,5.22 6.82,5.16C8.12,5.09 9.31,5.06 10.41,5.06L12,5C16.19,5 18.8,5.16 19.83,5.44C20.73,5.69 21.31,6.27 21.56,7.17Z\";\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/AroundMouseItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class AroundMouseItem : IVideoItem\n    {\n        readonly Settings _settings;\n        readonly IPlatformServices _platformServices;\n\n        public AroundMouseItem(Settings Settings, IPlatformServices PlatformServices)\n        {\n            _settings = Settings;\n            _platformServices = PlatformServices;\n        }\n\n        public string Name => null;\n\n        public IImageProvider GetImageProvider(bool IncludeCursor)\n        {\n            return new AroundMouseImageProvider(_settings.AroundMouse.Width,\n                _settings.AroundMouse.Height,\n                _settings.AroundMouse.Margin,\n                _platformServices,\n                IncludeCursor);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/Models/AroundMouseSourceProvider.cs",
    "content": "﻿using System.Drawing;\nusing System.Text.RegularExpressions;\n\nnamespace Captura.Video\n{\n    public class AroundMouseSourceProvider : IVideoSourceProvider\n    {\n        readonly Settings _settings;\n        readonly IPlatformServices _platformServices;\n\n        public AroundMouseSourceProvider(IIconSet Icons,\n            AroundMouseItem AroundMouseItem,\n            Settings Settings,\n            IPlatformServices PlatformServices)\n        {\n            _settings = Settings;\n            _platformServices = PlatformServices;\n\n            Icon = Icons.Cursor;\n            Source = AroundMouseItem;\n        }\n\n        public string Name => \"Around Mouse\";\n\n        public string Description => \"Capture region surrounding mouse\";\n\n        public string Icon { get; }\n\n        public bool SupportsStepsMode => true;\n\n        public IVideoItem Source { get; }\n\n        public IBitmapImage Capture(bool IncludeCursor)\n        {\n            var cursorPos = _platformServices.CursorPosition;\n            var screenBounds = _platformServices.DesktopRectangle;\n            var w = _settings.AroundMouse.Width;\n            var h = _settings.AroundMouse.Height;\n\n            var region = new Rectangle(cursorPos.X - w / 2, cursorPos.Y - h / 2, w, h);\n\n            if (region.Right > screenBounds.Right)\n            {\n                region.X = screenBounds.Right - w;\n            }\n\n            if (region.Bottom > screenBounds.Bottom)\n            {\n                region.Y = screenBounds.Bottom - h;\n            }\n\n            if (region.X < screenBounds.X)\n            {\n                region.X = screenBounds.X;\n            }\n\n            if (region.Y < screenBounds.Y)\n            {\n                region.Y = screenBounds.Y;\n            }\n\n            return ScreenShot.Capture(region, IncludeCursor);\n        }\n\n        const string Key = \"aroundmouse\";\n\n        public bool Deserialize(string Serialized) => Serialized == Key;\n\n        public bool OnSelect() => true;\n\n        public void OnUnselect()\n        {\n        }\n\n        public bool ParseCli(string Arg)\n        {\n            var regex = new Regex($@\"^{Key}:(\\d+),(\\d+)$\");\n            var match = regex.Match(Arg);\n\n            if (match.Success)\n            {\n                _settings.AroundMouse.Width = int.Parse(match.Groups[1].Value);\n                _settings.AroundMouse.Height = int.Parse(match.Groups[2].Value);\n\n                return true;\n            }\n\n            return false;\n        }\n\n        public string Serialize() => Key;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/Models/Discard/DiscardWriter.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class DiscardWriter : IVideoFileWriter\n    {\n        public void Dispose() { }\n\n        public void WriteFrame(IBitmapFrame Image)\n        {\n            Image.Dispose();\n        }\n\n        public bool SupportsAudio => false;\n\n        public void WriteAudio(byte[] Buffer, int Offset, int Length) { }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Discard/DiscardWriterItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class DiscardWriterItem : IVideoWriterItem\n    {\n        readonly IPreviewWindow _previewWindow;\n\n        public DiscardWriterItem(IPreviewWindow PreviewWindow)\n        {\n            _previewWindow = PreviewWindow;\n        }\n\n        public string Extension { get; } = \"\";\n\n        public IVideoFileWriter GetVideoFileWriter(VideoWriterArgs Args)\n        {\n            _previewWindow.Show();\n\n            return new DiscardWriter();\n        }\n\n        public override string ToString() => \"Preview\";\n\n        public string Description => \"For testing purposes.\";\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Discard/DiscardWriterProvider.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\n\nnamespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class DiscardWriterProvider : IVideoWriterProvider\n    {\n        readonly IPreviewWindow _previewWindow;\n\n        public DiscardWriterProvider(IPreviewWindow PreviewWindow)\n        {\n            _previewWindow = PreviewWindow;\n        }\n\n        public IEnumerator<IVideoWriterItem> GetEnumerator()\n        {\n            yield return new DiscardWriterItem(_previewWindow);\n        }\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n\n        public string Name { get; } = \"Preview Only\";\n\n        public string Description => \"For testing purposes.\";\n\n        public override string ToString() => Name;\n\n        public IVideoWriterItem ParseCli(string Cli) => null;\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/EditorWriter.cs",
    "content": "﻿using System.IO;\nusing System.Threading.Tasks;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class EditorWriter : NotifyPropertyChanged, IImageWriterItem\n    {\n        public Task Save(IBitmapImage Image, ImageFormats Format, string FileName)\n        {\n            if (!File.Exists(FileName))\n            {\n                Image.Save(FileName, Format);\n            }\n\n            var winserv = ServiceProvider.Get<IMainWindow>();\n            winserv.EditImage(FileName);\n\n            return Task.CompletedTask;\n        }\n\n        public string Display => \"Editor\";\n\n        bool _active;\n\n        public bool Active\n        {\n            get => _active;\n            set => Set(ref _active, value);\n        }\n\n        public override string ToString() => Display;\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/ImageWriterItems/ClipboardWriter.cs",
    "content": "﻿using System.Threading.Tasks;\nusing Captura.Loc;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ClipboardWriter : NotifyPropertyChanged, IImageWriterItem\n    {\n        readonly ISystemTray _systemTray;\n        readonly IClipboardService _clipboard;\n        readonly ILocalizationProvider _loc;\n\n        public ClipboardWriter(ISystemTray SystemTray,\n            ILocalizationProvider Loc,\n            IClipboardService Clipboard)\n        {\n            _systemTray = SystemTray;\n            _loc = Loc;\n            _clipboard = Clipboard;\n\n            Loc.LanguageChanged += L => RaisePropertyChanged(nameof(Display));\n        }\n\n        public Task Save(IBitmapImage Image, ImageFormats Format, string FileName)\n        {\n            _clipboard.SetImage(Image);\n\n            _systemTray.ShowNotification(new TextNotification(_loc.ImgSavedClipboard));\n\n            return Task.CompletedTask;\n        }\n\n        public string Display => _loc.Clipboard;\n\n        bool _active;\n\n        public bool Active\n        {\n            get => _active;\n            set => Set(ref _active, value);\n        }\n\n        public override string ToString() => Display;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/Models/ImageWriterItems/DiskWriter.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Captura.Loc;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class DiskWriter : NotifyPropertyChanged, IImageWriterItem\n    {\n        readonly ISystemTray _systemTray;\n        readonly IMessageProvider _messageProvider;\n        readonly Settings _settings;\n        readonly ILocalizationProvider _loc;\n        readonly IRecentList _recentList;\n\n        public DiskWriter(ISystemTray SystemTray,\n            IMessageProvider MessageProvider,\n            Settings Settings,\n            ILocalizationProvider Loc,\n            IRecentList RecentList)\n        {\n            _systemTray = SystemTray;\n            _messageProvider = MessageProvider;\n            _settings = Settings;\n            _loc = Loc;\n            _recentList = RecentList;\n\n            Loc.LanguageChanged += L => RaisePropertyChanged(nameof(Display));\n        }\n\n        public Task Save(IBitmapImage Image, ImageFormats Format, string FileName)\n        {\n            try\n            {\n                var extension = Format.ToString().ToLower();\n\n                var fileName = _settings.GetFileName(extension, FileName);\n\n                Image.Save(fileName, Format);\n                \n                _recentList.Add(new FileRecentItem(fileName, RecentFileType.Image));\n\n                // Copy path to clipboard only when clipboard writer is off\n                if (_settings.CopyOutPathToClipboard && !ServiceProvider.Get<ClipboardWriter>().Active)\n                    fileName.WriteToClipboard();\n\n                _systemTray.ShowScreenShotNotification(fileName);\n            }\n            catch (Exception e)\n            {\n                _messageProvider.ShowException(e, _loc.NotSaved);\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public string Display => _loc.Disk;\n\n        bool _active;\n\n        public bool Active\n        {\n            get => _active;\n            set => Set(ref _active, value);\n        }\n\n        public override string ToString() => Display;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/Models/ImageWriterItems/ImageUploadWriter.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Captura.Loc;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ImageUploadWriter : NotifyPropertyChanged, IImageWriterItem\n    {\n        readonly DiskWriter _diskWriter;\n        readonly ISystemTray _systemTray;\n        readonly IMessageProvider _messageProvider;\n        readonly Settings _settings;\n        readonly ILocalizationProvider _loc;\n        readonly IRecentList _recentList;\n\n        readonly IImageUploader _imgUploader;\n\n        public ImageUploadWriter(DiskWriter DiskWriter,\n            ISystemTray SystemTray,\n            IMessageProvider MessageProvider,\n            Settings Settings,\n            ILocalizationProvider Loc,\n            IRecentList RecentList,\n            IImageUploader ImgUploader)\n        {\n            _imgUploader = ImgUploader;\n\n            _diskWriter = DiskWriter;\n            _systemTray = SystemTray;\n            _messageProvider = MessageProvider;\n            _settings = Settings;\n            _loc = Loc;\n            _recentList = RecentList;\n\n            Loc.LanguageChanged += L => RaisePropertyChanged(nameof(Display));\n        }\n\n        public async Task Save(IBitmapImage Image, ImageFormats Format, string FileName)\n        {\n            var response = await Save(Image, Format);\n\n            switch (response)\n            {\n                case UploadResult uploadResult:\n                    var link = uploadResult.Url;\n\n                    // Copy path to clipboard only when clipboard writer is off\n                    if (_settings.CopyOutPathToClipboard && !ServiceProvider.Get<ClipboardWriter>().Active)\n                        link.WriteToClipboard();\n                    break;\n\n                case Exception e:\n                    if (!_diskWriter.Active)\n                    {\n                        ServiceProvider.Get<IMainWindow>().IsVisible = true;\n\n                        var yes = _messageProvider.ShowYesNo(\n                            $\"{e.Message}\\n\\nDo you want to Save to Disk?\", _loc.ImageUploadFailed);\n\n                        if (yes)\n                            await _diskWriter.Save(Image, Format, FileName);\n                    }\n                    break;\n            }\n        }\n\n        // Returns UploadResult on success, Exception on failure\n        public async Task<object> Save(IBitmapImage Image, ImageFormats Format)\n        {\n            var progressItem = new ImageUploadNotification();\n            _systemTray.ShowNotification(progressItem);\n\n            try\n            {\n                var uploadResult = await _imgUploader.Upload(Image, Format, M => progressItem.Progress = M);\n\n                var link = uploadResult.Url;\n\n                _recentList.Add(new UploadRecentItem(link, uploadResult.DeleteLink, _imgUploader));\n\n                progressItem.RaiseFinished(link);\n\n                return uploadResult;\n            }\n            catch (Exception e)\n            {\n                progressItem.RaiseFailed();\n\n                return e;\n            }\n        }\n\n        public string Display => \"Upload\";\n\n        bool _active;\n\n        public bool Active\n        {\n            get => _active;\n            set => Set(ref _active, value);\n        }\n\n        public override string ToString() => Display;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/Models/NoVideoItem.cs",
    "content": "﻿using Captura.Audio;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Holds codecs for audio-alone capture.\n    /// </summary>\n    public class NoVideoItem : IVideoItem\n    {\n        public IAudioWriterItem AudioWriterItem { get; }\n\n        public NoVideoItem(IAudioWriterItem AudioWriterItem)\n        {\n            this.AudioWriterItem = AudioWriterItem;\n        }\n\n        public string Name => AudioWriterItem.Name;\n\n        public IImageProvider GetImageProvider(bool IncludeCursor)\n        {\n            return null;\n        }\n\n        public override string ToString() => Name;\n\n        public string Extension => AudioWriterItem.Extension;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/Models/NoVideoSourceProvider.cs",
    "content": "using Captura.Audio;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Captura.Loc;\n\nnamespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class NoVideoSourceProvider : VideoSourceProviderBase\n    {\n        public NoVideoSourceProvider(ILocalizationProvider Loc,\n            IIconSet Icons,\n            IEnumerable<IAudioWriterItem> AudioWriterItems) : base(Loc)\n        {\n            Sources = AudioWriterItems\n                .Select(M => new NoVideoItem(M))\n                .ToArray<IVideoItem>();\n\n            Icon = Icons.NoVideo;\n\n            if (Sources.Length > 0)\n                SelectedSource = Sources[0];\n        }\n\n        public override bool SupportsStepsMode => false;\n\n        public IVideoItem[] Sources { get; }\n\n        IVideoItem _selectedSource;\n\n        public IVideoItem SelectedSource\n        {\n            get => _selectedSource;\n            set\n            {\n                _selectedSource = value;\n                \n                OnPropertyChanged();\n\n                RaisePropertyChanged(nameof(Source));\n            }\n        }\n\n        public override IVideoItem Source => _selectedSource;\n\n        public override string Name => Loc.OnlyAudio;\n\n        public override string Description { get; } = @\"No Video recorded.\nCan be used for audio-only recording.\nMake sure Audio sources are enabled.\";\n\n        public override string Icon { get; }\n\n        public override bool Deserialize(string Serialized)\n        {\n            var source = Sources.FirstOrDefault(M => M.Name == Serialized);\n\n            if (source == null)\n                return false;\n\n            SelectedSource = source;\n\n            return true;\n        }\n\n        public override bool ParseCli(string Arg)\n        {\n            return Arg == \"none\";\n        }\n\n        public override IBitmapImage Capture(bool IncludeCursor) => null;\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Notifications/FileSaveNotification.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.IO;\nusing Captura.Loc;\nusing Captura.Models;\n\nnamespace Captura\n{\n    public class FileSaveNotification : NotifyPropertyChanged, INotification\n    {\n        readonly FileRecentItem _recentItem;\n        readonly ILocalizationProvider _loc;\n        readonly IIconSet _icons;\n\n        string _fileName;\n\n        public FileSaveNotification(FileRecentItem RecentItem)\n        {\n            _recentItem = RecentItem;\n\n            _loc = ServiceProvider.Get<ILocalizationProvider>();\n            _icons = ServiceProvider.Get<IIconSet>();\n\n            _fileName = RecentItem.FileName;\n\n            PrimaryText = $\"Saving {_recentItem.FileType} ...\";\n            SecondaryText = Path.GetFileName(_fileName);\n        }\n\n        public void Converting()\n        {\n            PrimaryText = \"Converting ...\";\n        }\n\n        public void Converted(string NewFileName)\n        {\n            SecondaryText = Path.GetFileName(NewFileName);\n            _fileName = NewFileName;\n        }\n\n        public void Saved()\n        {\n            var deleteAction = new NotificationAction\n            {\n                Icon = _icons.Delete,\n                Name = _loc.Delete,\n                Color = \"LightPink\"\n            };\n\n            deleteAction.Click += () =>\n            {\n                if (File.Exists(_fileName))\n                {\n                    var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n                    if (!platformServices.DeleteFile(_fileName))\n                        return;\n                }\n\n                Remove();\n\n                OnDelete?.Invoke();\n            };\n\n            _notificationActions.Add(deleteAction);\n\n            PrimaryText = _recentItem.FileType == RecentFileType.Video ? _loc.VideoSaved : _loc.AudioSaved;\n            Finished = true;\n        }\n\n        public event Action RemoveRequested;\n\n        public event Action OnDelete;\n\n        public void RaiseClick()\n        {\n            if (_recentItem.IsSaving)\n                return;\n\n            ServiceProvider.LaunchFile(new ProcessStartInfo(_fileName));\n        }\n\n        public void Remove() => RemoveRequested?.Invoke();\n\n        readonly ObservableCollection<NotificationAction> _notificationActions = new ObservableCollection<NotificationAction>();\n\n        public IEnumerable<NotificationAction> Actions => _notificationActions;\n\n        int _progress;\n\n        public int Progress\n        {\n            get => _progress;\n            set => Set(ref _progress, value);\n        }\n\n        string _primaryText;\n\n        public string PrimaryText\n        {\n            get => _primaryText;\n            private set => Set(ref _primaryText, value);\n        }\n\n        string _secondaryText;\n\n        public string SecondaryText\n        {\n            get => _secondaryText;\n            private set => Set(ref _secondaryText, value);\n        }\n\n        bool _finished;\n\n        public bool Finished\n        {\n            get => _finished;\n            private set => Set(ref _finished, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Notifications/ImageUploadNotification.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing Captura.Loc;\nusing Captura.Models;\n\nnamespace Captura\n{\n    public class ImageUploadNotification : NotifyPropertyChanged, INotification\n    {\n        readonly ILocalizationProvider _loc;\n\n        public ImageUploadNotification()\n        {\n            _loc = ServiceProvider.Get<ILocalizationProvider>();\n\n            PrimaryText = _loc.ImageUploading;\n        }\n\n        public event Action RemoveRequested;\n\n        public void Remove() => RemoveRequested?.Invoke();\n\n        public void RaiseClick()\n        {\n            if (_link != null)\n            {\n                Process.Start(_link);\n            }\n        }\n\n        public void RaiseFailed()\n        {\n            Finished = true;\n\n            PrimaryText = _loc.ImageUploadFailed;\n        }\n\n        string _link;\n\n        public void RaiseFinished(string Link)\n        {\n            _link = Link;\n\n            Finished = true;\n            PrimaryText = _loc.ImageUploadSuccess;\n            SecondaryText = Link;\n\n            var icons = ServiceProvider.Get<IIconSet>();\n\n            var copyLinkAction = AddAction();\n            copyLinkAction.Name = _loc.CopyToClipboard;\n            copyLinkAction.Icon = icons.Link;\n            copyLinkAction.Click += Link.WriteToClipboard;\n        }\n\n        readonly ObservableCollection<NotificationAction> _actions = new ObservableCollection<NotificationAction>();\n\n        public IEnumerable<NotificationAction> Actions => _actions;\n\n        readonly SyncContextManager _syncContext = new SyncContextManager();\n\n        NotificationAction AddAction()\n        {\n            var action = new NotificationAction();\n\n            _syncContext.Run(() => _actions.Add(action));\n\n            return action;\n        }\n\n        int _progress;\n\n        public int Progress\n        {\n            get => _progress;\n            set => Set(ref _progress, value);\n        }\n\n        string _primaryText, _secondaryText;\n\n        public string PrimaryText\n        {\n            get => _primaryText;\n            private set => Set(ref _primaryText, value);\n        }\n\n        public string SecondaryText\n        {\n            get => _secondaryText;\n            private set => Set(ref _secondaryText, value);\n        }\n\n        bool _finished;\n\n        public bool Finished\n        {\n            get => _finished;\n            private set => Set(ref _finished, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Notifications/TextNotification.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Captura\n{\n    public class TextNotification : INotification\n    {\n        readonly Action _onClick;\n\n        public TextNotification(string PrimaryText, Action OnClick = null, string SecondaryText = null)\n        {\n            _onClick = OnClick;\n\n            this.PrimaryText = PrimaryText;\n            this.SecondaryText = SecondaryText;\n        }\n\n        public int Progress => 0;\n\n        public string PrimaryText { get; }\n        public string SecondaryText { get; }\n\n        bool INotification.Finished => true;\n\n        public IEnumerable<NotificationAction> Actions { get; } = new NotificationAction[0];\n\n        public void RaiseClick() => _onClick?.Invoke();\n\n        public void Remove() => RemoveRequested?.Invoke();\n\n        public event Action RemoveRequested;\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Recents/FileRecentItem.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Windows.Input;\nusing Captura.Loc;\n\nnamespace Captura.Models\n{\n    public class FileRecentItem : NotifyPropertyChanged, IRecentItem\n    {\n        string _fileName;\n\n        public string FileName\n        {\n            get => _fileName;\n            private set\n            {\n                Set(ref _fileName, value);\n\n                Display = Path.GetFileName(value);\n            }\n        }\n\n        public RecentFileType FileType { get; }\n\n        public FileRecentItem(string FileName, RecentFileType FileType, bool IsSaving = false)\n        {\n            this.FileName = FileName;\n            this.FileType = FileType;\n            this.IsSaving = IsSaving;\n\n            ClickCommand = new DelegateCommand(() => ServiceProvider.LaunchFile(new ProcessStartInfo(this.FileName)));\n\n            RemoveCommand = new DelegateCommand(() => RemoveRequested?.Invoke());\n\n            var icons = ServiceProvider.Get<IIconSet>();\n            var loc = ServiceProvider.Get<ILocalizationProvider>();\n            var windowService = ServiceProvider.Get<IMainWindow>();\n\n            Icon = GetIcon(FileType, icons);\n            IconColor = GetColor(FileType);\n\n            var list = new List<RecentAction>\n            {\n                new RecentAction(loc.CopyPath, icons.Clipboard, () => this.FileName.WriteToClipboard())\n            };\n\n            void AddTrimMedia()\n            {\n                list.Add(new RecentAction(loc.Trim, icons.Trim, () => windowService.TrimMedia(this.FileName)));\n            }\n\n            switch (FileType)\n            {\n                case RecentFileType.Image:\n                    list.Add(new RecentAction(loc.CopyToClipboard, icons.Clipboard, OnCopyToClipboardExecute));\n                    list.Add(new RecentAction(loc.UploadToImgur, icons.Upload, OnUploadToImgurExecute));\n                    list.Add(new RecentAction(loc.Edit, icons.Pencil, () => windowService.EditImage(this.FileName)));\n                    break;\n\n                case RecentFileType.Audio:\n                    AddTrimMedia();\n                    break;\n\n                case RecentFileType.Video:\n                    AddTrimMedia();\n                    list.Add(new RecentAction(\"Upload to YouTube\", icons.YouTube, () => windowService.UploadToYouTube(this.FileName)));\n                    break;\n            }\n\n            list.Add(new RecentAction(loc.Delete, icons.Delete, OnDelete));\n\n            Actions = list;\n        }\n\n        async void OnUploadToImgurExecute()\n        {\n            if (!File.Exists(FileName))\n            {\n                ServiceProvider.MessageProvider.ShowError(\"File not Found\");\n\n                return;\n            }\n\n            var imgSystem = ServiceProvider.Get<IImagingSystem>();\n\n            using var img = imgSystem.LoadBitmap(FileName);\n            await img.UploadImage();\n        }\n\n        void OnCopyToClipboardExecute()\n        {\n            if (!File.Exists(FileName))\n            {\n                ServiceProvider.MessageProvider.ShowError(\"File not Found\");\n\n                return;\n            }\n\n            try\n            {\n                var clipboard = ServiceProvider.Get<IClipboardService>();\n\n                var imgSystem = ServiceProvider.Get<IImagingSystem>();\n\n                using var img = imgSystem.LoadBitmap(FileName);\n                clipboard.SetImage(img);\n            }\n            catch (Exception e)\n            {\n                ServiceProvider.MessageProvider.ShowException(e, \"Copy to Clipboard failed\");\n            }\n        }\n\n        void OnDelete()\n        {\n            if (File.Exists(FileName))\n            {\n                var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n                if (!platformServices.DeleteFile(FileName))\n                    return;\n            }\n\n            // Remove from List\n            RemoveRequested?.Invoke();\n        }\n\n        static string GetIcon(RecentFileType ItemType, IIconSet Icons)\n        {\n            switch (ItemType)\n            {\n                case RecentFileType.Audio:\n                    return Icons.Music;\n\n                case RecentFileType.Image:\n                    return Icons.Image;\n\n                case RecentFileType.Video:\n                    return Icons.Video;\n            }\n\n            return null;\n        }\n\n        static string GetColor(RecentFileType ItemType)\n        {\n            switch (ItemType)\n            {\n                case RecentFileType.Audio:\n                    return \"DodgerBlue\";\n\n                case RecentFileType.Image:\n                    return \"YellowGreen\";\n\n                case RecentFileType.Video:\n                    return \"OrangeRed\";\n            }\n\n            return null;\n        }\n\n        string _display;\n\n        public string Display\n        {\n            get => _display;\n            private set => Set(ref _display, value);\n        }\n\n        public string Icon { get; }\n        public string IconColor { get; }\n\n        bool _saving;\n\n        public bool IsSaving\n        {\n            get => _saving;\n            private set => Set(ref _saving, value);\n        }\n\n        public void Saved()\n        {\n            IsSaving = false;\n        }\n\n        public void Converted(string NewFileName)\n        {\n            FileName = NewFileName;\n        }\n\n        public event Action RemoveRequested;\n\n        public ICommand ClickCommand { get; }\n        public ICommand RemoveCommand { get; }\n\n        public IEnumerable<RecentAction> Actions { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Recents/FileRecentSerializer.cs",
    "content": "﻿using System.IO;\nusing Newtonsoft.Json.Linq;\n\nnamespace Captura.Models\n{\n    public class FileRecentSerializer : IRecentItemSerializer\n    {\n        public bool CanSerialize(IRecentItem Item) => Item is FileRecentItem;\n\n        public bool CanDeserialize(JObject Item)\n        {\n            return Item.ContainsKey(nameof(FileRecentModel.Type))\n                   && Item[nameof(FileRecentModel.Type)].ToString() == FileRecentModel.IdValue;\n        }\n\n        class FileRecentModel\n        {\n            public const string IdValue = \"File\";\n\n            public string Type => IdValue;\n\n            public RecentFileType FileType { get; set; }\n\n            public string FileName { get; set; }\n        }\n\n        public JObject Serialize(IRecentItem Item)\n        {\n            // Persist only if File exists or is a link.\n            if (Item is FileRecentItem item && File.Exists(item.FileName))\n            {\n                return JObject.FromObject(new FileRecentModel\n                {\n                    FileName = item.FileName,\n                    FileType = item.FileType\n                });\n            }\n\n            return null;\n        }\n\n        public IRecentItem Deserialize(JObject Item)\n        {\n            try\n            {\n                var model = Item.ToObject<FileRecentModel>();\n\n                // Restore only if file exists\n                return File.Exists(model.FileName)\n                    ? new FileRecentItem(model.FileName, model.FileType)\n                    : null;\n            }\n            catch\n            {\n                return null;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Recents/IRecentItemSerializer.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\n\nnamespace Captura.Models\n{\n    public interface IRecentItemSerializer\n    {\n        bool CanSerialize(IRecentItem Item);\n\n        bool CanDeserialize(JObject Item);\n\n        JObject Serialize(IRecentItem Item);\n\n        IRecentItem Deserialize(JObject Item);\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Recents/RecentFileType.cs",
    "content": "﻿namespace Captura.Models\n{\n    public enum RecentFileType\n    {\n        Image,\n        Video,\n        Audio\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Recents/RecentListRepository.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.IO;\nusing System.Linq;\nusing Newtonsoft.Json.Linq;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class RecentListRepository : IRecentList\n    {\n        readonly ObservableCollection<IRecentItem> _recentList = new ObservableCollection<IRecentItem>();\n\n        public ReadOnlyObservableCollection<IRecentItem> Items { get; }\n\n        readonly IEnumerable<IRecentItemSerializer> _recentItemSerializers;\n\n        static string GetFilePath()\n        {\n            return Path.Combine(ServiceProvider.SettingsDir, \"RecentItems.json\");\n        }\n\n        public RecentListRepository(IEnumerable<IRecentItemSerializer> RecentItemSerializers)\n        {\n            Items = new ReadOnlyObservableCollection<IRecentItem>(_recentList);\n\n            _recentItemSerializers = RecentItemSerializers;\n\n            Load();\n        }\n\n        void Load()\n        {\n            try\n            {\n                var json = File.ReadAllText(GetFilePath());\n\n                var jarray = JArray.Parse(json);\n\n                var items = new List<IRecentItem>();\n\n                foreach (var jItem in jarray)\n                {\n                    var jObj = (JObject)jItem;\n\n                    var serializer = _recentItemSerializers.FirstOrDefault(M => M.CanDeserialize(jObj));\n\n                    var item = serializer?.Deserialize(jObj);\n\n                    if (item != null)\n                    {\n                        items.Add(item);\n                    }\n                }\n\n                // Reversion required to maintain order\n                items.Reverse();\n\n                foreach (var model in items)\n                {\n                    Add(model);\n                }\n            }\n            catch\n            {\n                // Ignore Errors\n            }\n        }\n\n        public void Add(IRecentItem RecentItem)\n        {\n            // Insert on Top\n            _recentList.Insert(0, RecentItem);\n\n            RecentItem.RemoveRequested += () => _recentList.Remove(RecentItem);\n        }\n\n        public void Clear()\n        {\n            _recentList.Clear();\n        }\n\n        public void Dispose()\n        {\n            try\n            {\n                var items = new JArray();\n\n                foreach (var item in Items)\n                {\n                    var serializer = _recentItemSerializers.FirstOrDefault(M => M.CanSerialize(item));\n\n                    var jItem = serializer?.Serialize(item);\n\n                    if (jItem != null)\n                    {\n                        items.Add(jItem);\n                    }\n                }\n\n                var json = items.ToString();\n\n                File.WriteAllText(GetFilePath(), json);\n            }\n            catch\n            {\n                // Ignore Errors\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Recents/UploadRecentItem.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Windows.Input;\nusing Captura.Loc;\n\nnamespace Captura.Models\n{\n    public class UploadRecentItem : IRecentItem\n    {\n        public string DeleteHash { get; }\n        public string Link { get; }\n        public IImageUploader UploaderService { get; }\n\n        public UploadRecentItem(string Link, string DeleteHash, IImageUploader UploaderService)\n        {\n            this.DeleteHash = DeleteHash;\n            this.UploaderService = UploaderService;\n\n            ClickCommand = new DelegateCommand(() => ServiceProvider.LaunchFile(new ProcessStartInfo(Link)));\n\n            RemoveCommand = new DelegateCommand(() => RemoveRequested?.Invoke());\n\n            var icons = ServiceProvider.Get<IIconSet>();\n            var loc = ServiceProvider.Get<ILocalizationProvider>();\n\n            Display = this.Link = Link;\n            Icon = icons.Link;\n\n            Actions = new[]\n            {\n                new RecentAction(loc.CopyPath, icons.Clipboard, () => this.Link.WriteToClipboard()),\n                new RecentAction(loc.Delete, icons.Delete, OnDelete)\n            };\n        }\n\n        async void OnDelete()\n        {\n            if (!ServiceProvider.MessageProvider.ShowYesNo($\"Are you sure you want to Delete: {Link}?\", \"Confirm Deletion\"))\n                return;\n\n            try\n            {\n                await UploaderService.DeleteUploadedFile(DeleteHash);\n            }\n            catch (Exception e)\n            {\n                ServiceProvider.MessageProvider.ShowException(e, $\"Could not Delete: {Link}\");\n\n                return;\n            }\n\n            RemoveRequested?.Invoke();\n        }\n\n        public string Display { get; }\n\n        public string Icon { get; }\n\n        public string IconColor => \"MediumPurple\";\n\n        bool IRecentItem.IsSaving => false;\n\n        public ICommand ClickCommand { get; }\n\n        public ICommand RemoveCommand { get; }\n\n        public IEnumerable<RecentAction> Actions { get; }\n\n        public event Action RemoveRequested;\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/Recents/UploadRecentSerializer.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing Newtonsoft.Json.Linq;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class UploadRecentSerializer : IRecentItemSerializer\n    {\n        readonly IEnumerable<IImageUploader> _imgUploaders;\n\n        public UploadRecentSerializer(IEnumerable<IImageUploader> ImgUploaders)\n        {\n            _imgUploaders = ImgUploaders;\n        }\n\n        public bool CanSerialize(IRecentItem Item) => Item is UploadRecentItem;\n\n        public bool CanDeserialize(JObject Item)\n        {\n            return Item.ContainsKey(nameof(UploadRecentModel.Type))\n                   && Item[nameof(UploadRecentModel.Type)].ToString() == UploadRecentModel.IdValue;\n        }\n\n        class UploadRecentModel\n        {\n            public const string IdValue = \"Upload\";\n\n            public string Type => IdValue;\n\n            public string Link { get; set; }\n\n            public string DeleteHash { get; set; }\n\n            public string UploaderService { get; set; }\n        }\n\n        public JObject Serialize(IRecentItem Item)\n        {\n            if (Item is UploadRecentItem item)\n            {\n                return JObject.FromObject(new UploadRecentModel\n                {\n                    Link = item.Link,\n                    DeleteHash = item.DeleteHash,\n                    UploaderService = item.UploaderService.UploadServiceName\n                });\n            }\n\n            return null;\n        }\n\n        public IRecentItem Deserialize(JObject Item)\n        {\n            try\n            {\n                var model = Item.ToObject<UploadRecentModel>();\n\n                var uploader = _imgUploaders.FirstOrDefault(M => M.UploadServiceName == model.UploaderService);\n\n                return uploader != null\n                    ? new UploadRecentItem(model.Link, model.DeleteHash, uploader)\n                    : null;\n            }\n            catch\n            {\n                return null;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/RecorderState.cs",
    "content": "﻿namespace Captura.Models\n{\n    public enum RecorderState\n    {\n        Recording,\n        Paused,\n        NotRecording\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/Models/StepWriters/ImageFolderWriter.cs",
    "content": "﻿using System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\n\nnamespace Captura.Video\n{\n    public class ImageFolderWriter : IVideoFileWriter\n    {\n        readonly string _folderPath;\n        int _index;\n\n        public ImageFolderWriter(string OutputPath)\n        {\n            _folderPath = OutputPath;\n\n            Directory.CreateDirectory(_folderPath);\n        }\n\n        public void Dispose() { }\n\n        public void WriteFrame(IBitmapFrame Image)\n        {\n            if (Image is RepeatFrame)\n                return;\n\n            using (Image)\n            {\n                // TODO: Make independent of System.Drawing\n                using var bmp = new Bitmap(Image.Width, Image.Height);\n                var data = bmp.LockBits(new Rectangle(Point.Empty, new Size(Image.Width, Image.Height)), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);\n\n                try\n                {\n                    Image.CopyTo(data.Scan0);\n                }\n                finally\n                {\n                    bmp.UnlockBits(data);\n                }\n\n                var filePath = Path.Combine(_folderPath, $\"{_index:D3}.png\");\n\n                bmp.Save(filePath, ImageFormat.Png);\n            }\n\n            ++_index;\n        }\n\n        public bool SupportsAudio => false;\n\n        public void WriteAudio(byte[] Buffer, int Offset, int Length) { }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/StepWriters/ImageFolderWriterItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class ImageFolderWriterItem : IVideoWriterItem\n    {\n        public string Extension { get; } = \"\";\n\n        public IVideoFileWriter GetVideoFileWriter(VideoWriterArgs Args)\n        {\n            return new ImageFolderWriter(Args.FileName);\n        }\n\n        public override string ToString() => \"Images\";\n\n        public string Description => \"Writes images to a folder.\";\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/StepWriters/StepsVideoWriterItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class StepsVideoWriterItem : IVideoWriterItem\n    {\n        IVideoWriterItem _writerItem;\n\n        public StepsVideoWriterItem(IVideoWriterItem WriterItem)\n        {\n            _writerItem = WriterItem;\n        }\n\n        public string Extension => _writerItem.Extension;\n\n        public IVideoFileWriter GetVideoFileWriter(VideoWriterArgs Args)\n        {\n            Args.FrameRate = 1;\n\n            return _writerItem.GetVideoFileWriter(Args);\n        }\n\n        public override string ToString() => \"Video\";\n\n        public string Description => \"Writes as a Video.\";\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/UpdateCheckers/DevUpdateChecker.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json.Linq;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class DevUpdateChecker : IUpdateChecker\n    {\n        readonly ProxySettings _proxySettings;\n        readonly Version _currentVersion;\n\n        public DevUpdateChecker(ProxySettings ProxySettings)\n        {\n            _proxySettings = ProxySettings;\n\n            _currentVersion = ServiceProvider.AppVersion;\n        }\n\n        public void GoToDownloadsPage()\n        {\n            Process.Start(DownloadsUrl);\n        }\n\n        const string DownloadsUrl = \"https://ci.appveyor.com/project/MathewSachin/captura/branch/master\";\n        const string MasterBuildUrl = \"https://ci.appveyor.com/api/projects/MathewSachin/Captura/branch/master\";\n\n        public async Task<Version> Check()\n        {\n            using (var w = new WebClient { Proxy = _proxySettings.GetWebProxy() })\n            {\n                var result = await w.DownloadStringTaskAsync(MasterBuildUrl);\n\n                var jObj = JObject.Parse(result);\n\n                var version = Version.Parse(jObj[\"build\"][\"version\"].ToString());\n\n                if (version > _currentVersion)\n                {\n                    return version;\n                }\n            }\n\n            return null;\n        }\n\n        public string BuildName => _currentVersion.Build == 0 ? \"DEV\" : \"CI\";\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/UpdateCheckers/IUpdateChecker.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\n\nnamespace Captura.Models\n{\n    public interface IUpdateChecker\n    {\n        void GoToDownloadsPage();\n\n        Task<Version> Check();\n\n        string BuildName { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/UpdateCheckers/UpdateChecker.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json.Linq;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class UpdateChecker : IUpdateChecker\n    {\n        readonly ProxySettings _proxySettings;\n        readonly Version _currentVersion;\n\n        public UpdateChecker(ProxySettings ProxySettings)\n        {\n            _proxySettings = ProxySettings;\n\n            _currentVersion = ServiceProvider.AppVersion;\n        }\n\n        public void GoToDownloadsPage()\n        {\n            Process.Start(DownloadsUrl);\n        }\n\n        const string DownloadsUrl = \"https://mathewsachin.github.io/Captura/download\";\n        const string LatestReleaseUrl = \"https://api.github.com/repos/MathewSachin/Captura/releases/latest\";\n\n        public async Task<Version> Check()\n        {\n            using (var w = new WebClient { Proxy = _proxySettings.GetWebProxy() })\n            {\n                // User Agent header required by GitHub api\n                w.Headers.Add(\"user-agent\", nameof(Captura));\n\n                var result = await w.DownloadStringTaskAsync(LatestReleaseUrl);\n\n                var jObj = JObject.Parse(result);\n\n                // tag_name = v0.0.0 for stable releases\n                var version = Version.Parse(jObj[\"tag_name\"].ToString().Substring(1));\n\n                if (version > _currentVersion)\n                {\n                    return version;\n                }\n            }\n\n            return null;\n        }\n\n        public string BuildName => \"STABLE\";\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/WebcamSourceProvider.cs",
    "content": "﻿using Captura.Loc;\nusing Captura.Video;\nusing Captura.Windows.Gdi;\n\nnamespace Captura.Webcam\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class WebcamSourceProvider : NotifyPropertyChanged, IVideoSourceProvider\n    {\n        readonly ILocalizationProvider _loc;\n        readonly WebcamModel _webcamModel;\n\n        public WebcamSourceProvider(ILocalizationProvider Loc,\n            IIconSet Icons,\n            WebcamModel WebcamModel)\n        {\n            _loc = Loc;\n            _webcamModel = WebcamModel;\n            Icon = Icons.Webcam;\n            Source = new WebcamVideoItem(WebcamModel);\n\n            Loc.LanguageChanged += L => RaisePropertyChanged(nameof(Name));\n        }\n\n        public string Name => _loc.WebCam;\n\n        public string Description { get; } = \"Record Webcam only\";\n        public string Icon { get; }\n\n        public IVideoItem Source { get; }\n\n        public bool SupportsStepsMode => false;\n\n        public IBitmapImage Capture(bool IncludeCursor)\n        {\n            var webcamCapture = _webcamModel.InitCapture();\n\n            try\n            {\n                return webcamCapture.Value?.Capture(GraphicsBitmapLoader.Instance);\n            }\n            finally\n            {\n                _webcamModel.ReleaseCapture();\n            }\n        }\n\n        public bool OnSelect() => true;\n\n        public void OnUnselect()\n        {\n        }\n\n        public string Serialize() => \"\";\n\n        public bool Deserialize(string Serialized) => true;\n\n        public bool ParseCli(string Arg) => Arg == \"webcam\";\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Models/WebcamVideoItem.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.Webcam\n{\n    public class WebcamVideoItem : NotifyPropertyChanged, IVideoItem\n    {\n        readonly WebcamModel _webcamModel;\n\n        public WebcamVideoItem(WebcamModel WebcamModel)\n        {\n            _webcamModel = WebcamModel;\n\n            _webcamModel.PropertyChanged += (S, E) => RaisePropertyChanged(nameof(Name));\n        }\n\n        public string Name => _webcamModel.SelectedCam?.Name;\n\n        public IImageProvider GetImageProvider(bool IncludeCursor)\n        {\n            return new WebcamImageProvider(_webcamModel);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/NoWebcamItem.cs",
    "content": "using System;\nusing Captura.Loc;\n\nnamespace Captura.Webcam\n{\n    public class NoWebcamItem : NotifyPropertyChanged, IWebcamItem\n    {\n        NoWebcamItem()\n        {\n            var loc = ServiceProvider.Get<ILocalizationProvider>();\n\n            Name = loc.NoWebcam;\n\n            loc.LanguageChanged += L =>\n            {\n                Name = loc.NoWebcam;\n\n                RaisePropertyChanged(nameof(Name));\n            };\n        }\n\n        public string Name { get; private set; }\n\n        public IWebcamCapture BeginCapture(Action OnClick) => null;\n\n        public static IWebcamItem Instance { get; } = new NoWebcamItem();\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Settings/Models/AroundMouseSettings.cs",
    "content": "﻿namespace Captura\n{\n    public class AroundMouseSettings : PropertyStore\n    {\n        public int Width\n        {\n            get => Get(600);\n            set => Set(value);\n        }\n\n        public int Height\n        {\n            get => Get(400);\n            set => Set(value);\n        }\n\n        public int Margin\n        {\n            get => Get(30);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Settings/Models/ScreenShotSettings.cs",
    "content": "﻿namespace Captura\n{\n    public class ScreenShotSettings : PropertyStore\n    {\n        public ImageFormats ImageFormat\n        {\n            get => Get(ImageFormats.Png);\n            set => Set(value);\n        }\n\n        public string[] SaveTargets\n        {\n            get => Get(new []{ \"Disk\" });\n            set => Set(value);\n        }\n\n        public bool WindowShotTransparent\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n\n        public string ExternalEditor\n        {\n            get => Get(\"mspaint\");\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Settings/Models/SoundSettings.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Captura.Audio\n{\n    public class SoundSettings : PropertyStore\n    {\n        public Dictionary<SoundKind, string> Items { get; } = new Dictionary<SoundKind, string>();\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Settings/Models/TraySettings.cs",
    "content": "﻿using Captura.Hotkeys;\n\nnamespace Captura\n{\n    public class TraySettings : PropertyStore\n    {\n        public ServiceName LeftClickAction\n        {\n            get => Get(ServiceName.ShowMainWindow);\n            set => Set(value);\n        }\n\n        public bool ShowNotifications\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n\n        public bool MinToTrayOnStartup\n        {\n            get => Get(false);\n            set => Set(value);\n        }\n\n        public bool MinToTrayOnClose\n        {\n            get => Get(false);\n            set => Set(value);\n        }\n\n        public bool MinToTrayOnCaptureStart\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Settings/Models/VisualSettings.cs",
    "content": "﻿namespace Captura\n{\n    public class VisualSettings : PropertyStore\n    {\n        public bool DarkTheme\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n\n        public bool MainWindowTopmost\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n\n        public string AccentColor\n        {\n            get => Get<string>();\n            set => Set(value);\n        }\n\n        public int MainWindowLeft\n        {\n            get => Get(50);\n            set => Set(value);\n        }\n\n        public int MainWindowTop\n        {\n            get => Get(50);\n            set => Set(value);\n        }\n\n        public bool Expanded\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n\n        public bool HideOnFullScreenShot\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n\n        public string Language\n        {\n            get => Get(\"en\");\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Settings/Models/WebcamOverlaySettings.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura\n{\n    public class WebcamOverlaySettings : PropertyStore\n    {\n        public bool SeparateFile\n        {\n            get => Get(false);\n            set => Set(value);\n        }\n\n        public int Opacity\n        {\n            get => Get(100);\n            set => Set(value);\n        }\n\n        public double Scale\n        {\n            get => Get(0.3);\n            set => Set(value);\n        }\n\n        public double XLoc\n        {\n            get => Get(1.0);\n            set => Set(value);\n        }\n\n        public double YLoc\n        {\n            get => Get(1.0);\n            set => Set(value);\n        }\n\n        public Size GetSize(Size FrameSize, Size WebcamSize)\n        {\n            if (WebcamSize.Width == 0 || WebcamSize.Height == 0)\n            {\n                return Size.Empty;\n            }\n\n            var wByW = FrameSize.Width / (double)WebcamSize.Width;\n            var hByH = FrameSize.Height / (double)WebcamSize.Height;\n\n            if (wByW < hByH)\n            {\n                var w = (int)Math.Round(FrameSize.Width * Scale);\n                var scale = w / (double)WebcamSize.Width;\n                var h = (int)Math.Round(WebcamSize.Height * scale);\n\n                return new Size(w, h);\n            }\n            else\n            {\n                var h = (int)Math.Round(FrameSize.Height * Scale);\n                var scale = h / (double)WebcamSize.Height;\n                var w = (int)Math.Round(WebcamSize.Width * scale);\n\n                return new Size(w, h);\n            }\n        }\n\n        public Point GetPosition(Size FrameSize, Size WebcamSize)\n        {\n            var size = GetSize(FrameSize, WebcamSize);\n\n            var xLeft = FrameSize.Width - size.Width;\n            var yLeft = FrameSize.Height - size.Height;\n\n            var left = (int)Math.Round(xLeft * XLoc);\n            var top = (int)Math.Round(yLeft * YLoc);\n\n            return new Point(left, top);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/Settings/Settings.cs",
    "content": "﻿using System;\nusing System.Collections.ObjectModel;\nusing System.Drawing;\nusing System.IO;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Converters;\nusing Newtonsoft.Json.Linq;\nusing System.Linq;\nusing Captura.Audio;\nusing Captura.FFmpeg;\nusing Captura.Imgur;\nusing Captura.MouseKeyHook;\nusing Captura.Video;\nusing Captura.Windows;\n\nnamespace Captura\n{\n    public class Settings : PropertyStore\n    {\n        static Settings()\n        {\n            JsonConvert.DefaultSettings = () => new JsonSerializerSettings\n            {\n                Formatting = Formatting.Indented,\n                NullValueHandling = NullValueHandling.Ignore,\n                Converters = new JsonConverter[]\n                {\n                    new StringEnumConverter\n                    {\n                        AllowIntegerValues = false\n                    }\n                }\n            };\n        }\n\n        public Settings(FFmpegSettings FFmpeg, WindowsSettings WindowsSettings)\n        {\n            this.FFmpeg = FFmpeg;\n            this.WindowsSettings = WindowsSettings;\n        }\n\n        static string GetPath() => Path.Combine(ServiceProvider.SettingsDir, \"Captura.json\");\n\n        public bool Load()\n        {\n            try\n            {\n                var json = File.ReadAllText(GetPath());\n\n                JsonConvert.PopulateObject(json, this);\n\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        public bool Save()\n        {\n            try\n            {\n                var sortedProperties = JObject.FromObject(this).Properties().OrderBy(J => J.Name);\n\n                var jobj = new JObject(sortedProperties.Cast<object>().ToArray());\n\n                File.WriteAllText(GetPath(), jobj.ToString());\n\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        public ProxySettings Proxy { get; } = new ProxySettings();\n\n        public ImgurSettings Imgur { get; } = new ImgurSettings();\n\n        public WebcamOverlaySettings WebcamOverlay { get; set; } = new WebcamOverlaySettings();\n\n        public MouseOverlaySettings MousePointerOverlay { get; set; } = new MouseOverlaySettings\n        {\n            Color = Color.FromArgb(200, 239, 108, 0)\n        };\n\n        public MouseClickSettings Clicks { get; set; } = new MouseClickSettings();\n        \n        public KeystrokesSettings Keystrokes { get; set; } = new KeystrokesSettings();\n\n        public TextOverlaySettings Elapsed { get; set; } = new TextOverlaySettings();\n\n        public ObservableCollection<CensorOverlaySettings> Censored { get; } = new ObservableCollection<CensorOverlaySettings>();\n        \n        public VisualSettings UI { get; } = new VisualSettings();\n\n        public ScreenShotSettings ScreenShots { get; } = new ScreenShotSettings();\n\n        public VideoSettings Video { get; } = new VideoSettings();\n\n        public AudioSettings Audio { get; } = new AudioSettings();\n\n        public FFmpegSettings FFmpeg { get; }\n\n        public ObservableCollection<CustomOverlaySettings> TextOverlays { get; } = new ObservableCollection<CustomOverlaySettings>();\n\n        public ObservableCollection<CustomImageOverlaySettings> ImageOverlays { get; } = new ObservableCollection<CustomImageOverlaySettings>();\n\n        public SoundSettings Sounds { get; } = new SoundSettings();\n\n        public TraySettings Tray { get; } = new TraySettings();\n\n        public StepsSettings Steps { get; } = new StepsSettings();\n\n        public AroundMouseSettings AroundMouse { get; } = new AroundMouseSettings();\n\n        public WindowsSettings WindowsSettings { get; }\n\n        public int PreStartCountdown\n        {\n            get => Get(0);\n            set => Set(value);\n        }\n\n        public int Duration\n        {\n            get => Get(0);\n            set => Set(value);\n        }\n\n        public bool CopyOutPathToClipboard\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n\n        public string OutPath\n        {\n            get => Get<string>();\n            set => Set(value);\n        }\n\n        public string GetOutputPath()\n        {\n            var path = OutPath;\n\n            string DefaultOutDir() => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), nameof(Captura));\n\n            // If Output Dircetory is not set, fallback to default\n            path = string.IsNullOrWhiteSpace(path)\n                ? DefaultOutDir()\n                : path.Replace(ServiceProvider.CapturaPathConstant, ServiceProvider.AppDir);\n\n            // If drive is not present, fallback to default\n            if (!Directory.Exists(Path.GetPathRoot(path)))\n            {\n                path = DefaultOutDir();\n            }\n\n            if (!Directory.Exists(path))\n            {\n                Directory.CreateDirectory(path);\n            }\n\n            return path;\n        }\n\n        public string FilenameFormat\n        {\n            get => Get(\"%yyyy%-%MM%-%dd%/%HH%-%mm%-%ss%\");\n            set => Set(value);\n        }\n\n        public string GetFileName(string Extension, string FileName = null)\n        {\n            if (FileName != null)\n                return FileName;\n\n            if (!Extension.StartsWith(\".\"))\n                Extension = $\".{Extension}\";\n\n            var outPath = GetOutputPath();\n\n            if (string.IsNullOrWhiteSpace(FilenameFormat))\n                return Path.Combine(outPath, $\"{DateTime.Now:yyyy-MM-dd-HH-mm-ss}{Extension}\");\n\n            var now = DateTime.Now;\n\n            var filename = FilenameFormat\n                .Replace(\"%computer%\", Environment.MachineName)\n                .Replace(\"%user%\", Environment.UserName)\n\n                .Replace(\"%yyyy%\", now.ToString(\"yyyy\"))\n                .Replace(\"%yy%\", now.ToString(\"yy\"))\n                \n                .Replace(\"%MMMM%\", now.ToString(\"MMMM\"))\n                .Replace(\"%MMM%\", now.ToString(\"MMM\"))\n                .Replace(\"%MM%\", now.ToString(\"MM\"))\n                \n                .Replace(\"%dd%\", now.ToString(\"dd\"))\n                .Replace(\"%ddd%\", now.ToString(\"ddd\"))\n                .Replace(\"%dddd%\", now.ToString(\"dddd\"))\n                \n                .Replace(\"%HH%\", now.ToString(\"HH\"))\n                .Replace(\"%hh%\", now.ToString(\"hh\"))\n\n                .Replace(\"%mm%\", now.ToString(\"mm\"))\n                .Replace(\"%ss%\", now.ToString(\"ss\"))\n                .Replace(\"%tt%\", now.ToString(\"tt\"))\n                .Replace(\"%zzz%\", now.ToString(\"zzz\"));\n            \n            var path = Path.Combine(outPath, $\"{filename}{Extension}\");\n\n            var baseDir = Path.GetDirectoryName(path);\n            if (baseDir != null) \n                Directory.CreateDirectory(baseDir);\n\n            if (!File.Exists(path))\n                return path;\n\n            var i = 1;\n\n            do\n            {\n                path = Path.Combine(outPath, $\"{filename} ({i++}){Extension}\");\n            }\n            while (File.Exists(path));\n\n            return path;\n        }\n\n        public bool IncludeCursor\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n\n        public bool RegionPickerHotkeyAutoStartRecording\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Core/ViewModels/RecordingModel.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Captura.Audio;\nusing Captura.FFmpeg;\nusing Captura.Loc;\nusing Captura.Models;\nusing Captura.MouseKeyHook;\nusing Captura.MouseKeyHook.Steps;\nusing Captura.Video;\nusing Captura.Webcam;\nusing Microsoft.Win32;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class RecordingModel : ViewModelBase, IDisposable\n    {\n        #region Fields\n        IRecorder _recorder;\n        readonly SyncContextManager _syncContext = new SyncContextManager();\n\n        readonly ISystemTray _systemTray;\n        readonly IPreviewWindow _previewWindow;\n        readonly WebcamModel _webcamModel;\n        readonly TimerModel _timerModel;\n        readonly IMessageProvider _messageProvider;\n        readonly IFFmpegViewsProvider _ffmpegViewsProvider;\n\n        readonly KeymapViewModel _keymap;\n        readonly IAudioSource _audioSource;\n        readonly IFpsManager _fpsManager;\n\n        const int StepsRecorderFrameRate = 1;\n        #endregion\n\n        public RecordingModel(Settings Settings,\n            ILocalizationProvider Loc,\n            ISystemTray SystemTray,\n            IPreviewWindow PreviewWindow,\n            IAudioSource AudioSource,\n            WebcamModel WebcamModel,\n            KeymapViewModel Keymap,\n            TimerModel TimerModel,\n            IMessageProvider MessageProvider,\n            IFFmpegViewsProvider FFmpegViewsProvider,\n            IFpsManager FpsManager) : base(Settings, Loc)\n        {\n            _systemTray = SystemTray;\n            _previewWindow = PreviewWindow;\n            _audioSource = AudioSource;\n            _webcamModel = WebcamModel;\n            _keymap = Keymap;\n            _timerModel = TimerModel;\n            _messageProvider = MessageProvider;\n            _ffmpegViewsProvider = FFmpegViewsProvider;\n            _fpsManager = FpsManager;\n\n            SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;\n\n            TimerModel.CountdownElapsed += InternalStartRecording;\n        }\n\n        RecorderState _recorderState = RecorderState.NotRecording;\n\n        public RecorderState RecorderState\n        {\n            get => _recorderState;\n            private set => Set(ref _recorderState, value);\n        }\n\n        void SystemEvents_PowerModeChanged(object Sender, PowerModeChangedEventArgs E)\n        {\n            if (E.Mode == PowerModes.Suspend && RecorderState == RecorderState.Recording)\n            {\n                OnPauseExecute();\n            }\n        }\n\n        public void Dispose()\n        {\n            SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;\n        }\n\n        INotification _pauseNotification;\n\n        public void OnPauseExecute()\n        {\n            // Resume\n            if (RecorderState == RecorderState.Paused)\n            {\n                _systemTray.HideNotification();\n\n                _recorder.Start();\n                _timerModel.Resume();\n\n                RecorderState = RecorderState.Recording;\n\n                _pauseNotification?.Remove();\n            }\n            else // Pause\n            {\n                _recorder.Stop();\n                _timerModel.Pause();\n\n                RecorderState = RecorderState.Paused;\n\n                _pauseNotification = new TextNotification(Loc.Paused, OnPauseExecute);\n                _systemTray.ShowNotification(_pauseNotification);\n            }\n        }\n\n        bool GetImageProviderSafe(Func<IImageProvider> Getter, RecordingModelParams RecordingParams, out IImageProvider ImageProvider)\n        {\n            ImageProvider = null;\n\n            try\n            {\n                ImageProvider = Getter();\n\n                return true;\n            }\n            catch (WindowClosedException e)\n            {\n                _messageProvider.ShowException(e, \"Window Closed\");\n\n                return false;\n            }\n            catch (Exception e)\n            {\n                _messageProvider.ShowException(e, Loc.ErrorOccurred);\n\n                return false;\n            }\n        }\n\n        bool SetupVideoRecorder(IAudioProvider AudioProvider, RecordingModelParams RecordingParams, IMouseKeyHook MouseKeyHook)\n        {\n            IImageProvider ImgProviderGetter() => GetImageProviderWithOverlays(RecordingParams, MouseKeyHook);\n\n            if (!GetImageProviderSafe(ImgProviderGetter, RecordingParams, out var imgProvider))\n                return false;\n\n            IVideoFileWriter videoEncoder;\n\n            try\n            {\n                videoEncoder = GetVideoFileWriterWithPreview(imgProvider, AudioProvider, RecordingParams);\n            }\n            catch (FFmpegNotFoundException)\n            {\n                _ffmpegViewsProvider.ShowUnavailable();\n\n                imgProvider?.Dispose();\n\n                return false;\n            }\n            catch (Exception e)\n            {\n                _messageProvider.ShowException(e, e.Message);\n\n                imgProvider?.Dispose();\n\n                return false;\n            }\n\n            _recorder = new Recorder(videoEncoder, imgProvider, Settings.Video.FrameRate, AudioProvider, _fpsManager);\n\n            var webcamMode = RecordingParams.VideoSourceKind is WebcamSourceProvider;\n\n            // Separate file for webcam\n            if (!webcamMode\n                && !(_webcamModel.SelectedCam is NoWebcamItem)\n                && Settings.WebcamOverlay.SeparateFile)\n            {\n                SeparateFileForWebcam(RecordingParams);\n            }\n\n            // Separate file for every audio source\n            if (Settings.Audio.SeparateFilePerSource)\n            {\n                SeparateFileForEveryAudioSource(RecordingParams);\n            }\n\n            return true;\n        }\n\n        bool SetupAudioProvider(RecordingModelParams RecordingParams, out IAudioProvider AudioProvider)\n        {\n            AudioProvider = null;\n\n            try\n            {\n                if (!Settings.Audio.SeparateFilePerSource)\n                {\n                    AudioProvider = _audioSource.GetAudioProvider(\n                        Settings.Audio.RecordMicrophone ? RecordingParams.Microphone : null,\n                        Settings.Audio.RecordSpeaker ? RecordingParams.Speaker : null);\n                }\n            }\n            catch (Exception e)\n            {\n                _messageProvider.ShowException(e, e.Message);\n\n                return false;\n            }\n\n            return true;\n        }\n\n        bool SetupStepsRecorder(RecordingModelParams RecordingParams)\n        {\n            IImageProvider ImgProviderGetter() => GetImageProvider(RecordingParams);\n\n            if (!GetImageProviderSafe(ImgProviderGetter, RecordingParams, out var imgProvider))\n                return false;\n\n            IVideoFileWriter videoEncoder;\n\n            try\n            {\n                videoEncoder = GetVideoFileWriterWithPreview(imgProvider, null, RecordingParams);\n            }\n            catch (Exception e)\n            {\n                _messageProvider.ShowException(e, e.Message);\n\n                imgProvider?.Dispose();\n\n                return false;\n            }\n\n            var mouseKeyHook = new MouseKeyHook.MouseKeyHook();\n\n            _recorder = new StepsRecorder(mouseKeyHook,\n                videoEncoder,\n                imgProvider,\n                Settings.Clicks,\n                Settings.Keystrokes,\n                Settings.Steps,\n                _keymap);\n            \n            return true;\n        }\n\n        public bool StartRecording(RecordingModelParams RecordingParams, string FileName = null)\n        {\n            IsVideo = !(RecordingParams.VideoSourceKind is NoVideoSourceProvider);\n\n            var extension = RecordingParams.VideoWriter.Extension;\n\n            if (RecordingParams.VideoSourceKind?.Source is NoVideoItem x)\n                extension = x.Extension;\n\n            CurrentFileName = Settings.GetFileName(extension, FileName);\n\n            if (Settings.Video.RecorderMode == RecorderMode.Steps)\n            {\n                if (!SetupStepsRecorder(RecordingParams))\n                    return false;\n            }\n            else\n            {\n                if (!SetupAudioProvider(RecordingParams, out var audioProvider))\n                    return false;\n\n                if (IsVideo)\n                {\n                    var mouseKeyHook = new MouseKeyHook.MouseKeyHook();\n\n                    if (!SetupVideoRecorder(audioProvider, RecordingParams, mouseKeyHook))\n                    {\n                        mouseKeyHook.Dispose();\n\n                        audioProvider?.Dispose();\n\n                        return false;\n                    }\n                }\n                else if (RecordingParams.VideoSourceKind?.Source is NoVideoItem audioWriter)\n                {\n                    if (!InitAudioRecorder(audioWriter, audioProvider, RecordingParams))\n                    {\n                        audioProvider?.Dispose();\n\n                        return false;\n                    }\n                }\n            }\n\n\n            RecorderState = RecorderState.Recording;\n\n            _recorder.ErrorOccurred += OnErrorOccured;\n\n            if (Settings.PreStartCountdown == 0)\n            {\n                InternalStartRecording();\n            }\n\n            _timerModel.Start();\n\n            return true;\n        }\n\n        IRecorder GetAudioRecorder(NoVideoItem AudioWriter, IAudioProvider AudioProvider, string AudioFileName = null)\n        {\n            var audioFileWriter = AudioWriter.AudioWriterItem.GetAudioFileWriter(\n                AudioFileName ?? CurrentFileName,\n                AudioProvider?.WaveFormat,\n                Settings.Audio.Quality);\n\n            return new AudioRecorder(audioFileWriter, AudioProvider);\n        }\n\n        string GetAudioFileName(int Index)\n        {\n            return Path.ChangeExtension(CurrentFileName,\n                $\".{Index}{Path.GetExtension(CurrentFileName)}\");\n        }\n\n        bool InitAudioRecorder(NoVideoItem AudioWriter, IAudioProvider AudioProvider, RecordingModelParams RecordingParams)\n        {\n            try\n            {\n                // Not separate files or not multiple sources\n                if (!Settings.Audio.SeparateFilePerSource || !(Settings.Audio.RecordMicrophone && Settings.Audio.RecordSpeaker))\n                {\n                    _recorder = GetAudioRecorder(AudioWriter, AudioProvider);\n                }\n                else\n                {\n                    var audioProviders = new[]\n                    {\n                        _audioSource.GetAudioProvider(RecordingParams.Microphone, null),\n                        _audioSource.GetAudioProvider(null, RecordingParams.Speaker)\n                    }\n                    .Where(M => M != null)\n                    .ToArray();\n\n                    var recorders = audioProviders\n                        .Select((M, Index) => GetAudioRecorder(AudioWriter, M, GetAudioFileName(Index)))\n                        .ToArray();\n\n                    _recorder = new MultiRecorder(recorders);\n\n                    // Set to first file\n                    CurrentFileName = GetAudioFileName(0);\n                }\n            }\n            catch (FFmpegNotFoundException)\n            {\n                _ffmpegViewsProvider.ShowUnavailable();\n\n                return false;\n            }\n\n            return true;\n        }\n\n        void SeparateFileForWebcam(RecordingModelParams RecordingParams)\n        {\n            var webcamImgProvider = new WebcamImageProvider(_webcamModel);\n\n            var webcamFileName = Path.ChangeExtension(CurrentFileName, $\".webcam{Path.GetExtension(CurrentFileName)}\");\n\n            var webcamVideoWriter = GetVideoFileWriter(webcamImgProvider, null, RecordingParams, webcamFileName);\n\n            var webcamRecorder = new Recorder(webcamVideoWriter, webcamImgProvider, Settings.Video.FrameRate);\n\n            _recorder = new MultiRecorder(_recorder, webcamRecorder);\n        }\n\n        void SeparateFileForEveryAudioSource(RecordingModelParams RecordingParams)\n        {\n            var audioWriter = new WaveItem();\n\n            IRecorder GetAudioRecorder(IAudioProvider AudioProvider, string AudioFileName = null)\n            {\n                return new AudioRecorder(\n                    audioWriter.GetAudioFileWriter(AudioFileName ?? CurrentFileName, AudioProvider?.WaveFormat,\n                        Settings.Audio.Quality), AudioProvider);\n            }\n\n            string GetAudioFileName(int Index)\n            {\n                return Path.ChangeExtension(CurrentFileName, $\".{Index}.wav\");\n            }\n\n            var audioProviders = new[]\n            {\n                _audioSource.GetAudioProvider(RecordingParams.Microphone, null),\n                _audioSource.GetAudioProvider(null, RecordingParams.Speaker)\n            }\n            .Where(M => M != null)\n            .ToArray();\n\n            if (audioProviders.Length > 0)\n            {\n                var recorders = audioProviders\n                    .Select((M, Index) => GetAudioRecorder(M, GetAudioFileName(Index)))\n                    .Concat(new[] {_recorder})\n                    .ToArray();\n\n                _recorder = new MultiRecorder(recorders);\n            }\n        }\n\n        void InternalStartRecording()\n        {\n            _recorder.Start();\n        }\n\n        void OnErrorOccured(Exception E)\n        {\n            _syncContext.Run(() =>\n            {\n                var cancelled = E is WindowClosedException;\n\n                AfterRecording();\n\n                if (!cancelled)\n                    _messageProvider.ShowException(E, E.Message);\n            });\n        }\n\n        void AfterRecording()\n        {\n            _pauseNotification?.Remove();\n\n            RecorderState = RecorderState.NotRecording;\n\n            _recorder.ErrorOccurred -= OnErrorOccured;\n            _recorder = null;\n\n            _timerModel.Stop();\n        }\n\n        IVideoFileWriter GetVideoFileWriterWithPreview(IImageProvider ImgProvider, IAudioProvider AudioProvider, RecordingModelParams RecordingParams)\n        {\n            return RecordingParams.VideoSourceKind is NoVideoSourceProvider\n                ? null\n                : new WithPreviewWriter(GetVideoFileWriter(ImgProvider, AudioProvider, RecordingParams), _previewWindow);\n        }\n\n        IVideoFileWriter GetVideoFileWriter(IImageProvider ImgProvider, IAudioProvider AudioProvider, RecordingModelParams RecordingParams, string FileName = null)\n        {\n            if (RecordingParams.VideoSourceKind is NoVideoSourceProvider)\n                return null;\n\n            var args = new VideoWriterArgs\n            {\n                FileName = FileName ?? CurrentFileName,\n                FrameRate = Settings.Video.FrameRate,\n                VideoQuality = Settings.Video.Quality,\n                ImageProvider = ImgProvider,\n                AudioQuality = Settings.Audio.Quality,\n                AudioProvider = AudioProvider\n            };\n\n            if (Settings.Video.RecorderMode == RecorderMode.Replay)\n            {\n                return new FFmpegReplayWriter(args,\n                    Settings.Video.ReplayDuration,\n                    M => RecordingParams.VideoWriter.GetVideoFileWriter(M));\n            }\n            else return RecordingParams.VideoWriter.GetVideoFileWriter(args);\n        }\n\n        IEnumerable<IOverlay> GetOverlays(RecordingModelParams RecordingParams, IMouseKeyHook MouseKeyHook)\n        {\n            // No mouse and webcam overlays in webcam mode\n            var webcamMode = RecordingParams.VideoSourceKind is WebcamSourceProvider;\n\n            yield return new CensorOverlay(Settings.Censored);\n\n            if (!webcamMode && !Settings.WebcamOverlay.SeparateFile)\n            {\n                yield return new WebcamOverlay(_webcamModel, Settings);\n            }\n\n            if (!webcamMode)\n            {\n                yield return new MousePointerOverlay(Settings.MousePointerOverlay);\n            }\n\n            var clickSettings = webcamMode\n                ? new MouseClickSettings { Display = false }\n                : Settings.Clicks;\n\n            yield return new MouseKeyOverlay(MouseKeyHook,\n                clickSettings,\n                Settings.Keystrokes,\n                _keymap,\n                CurrentFileName,\n                () => _timerModel.TimeSpan);\n\n            yield return new ElapsedOverlay(Settings.Elapsed, () => _timerModel.TimeSpan);\n\n            // Text Overlays\n            foreach (var overlay in Settings.TextOverlays)\n            {\n                yield return new CustomOverlay(overlay);\n            }\n\n            // Image Overlays\n            foreach (var overlay in Settings.ImageOverlays.Where(M => M.Display))\n            {\n                IOverlay imgOverlay = null;\n\n                try\n                {\n                    imgOverlay = new CustomImageOverlay(overlay);\n                }\n                catch\n                {\n                    // Ignore Errors like Image not found, Invalid Image\n                }\n\n                if (imgOverlay != null)\n                    yield return imgOverlay;\n            }\n        }\n\n        IImageProvider GetImageProviderWithOverlays(RecordingModelParams RecordingParams, IMouseKeyHook MouseKeyHook)\n        {\n            var imageProvider = GetImageProvider(RecordingParams);\n\n            return imageProvider == null\n                ? null\n                : new OverlayedImageProvider(imageProvider, GetOverlays(RecordingParams, MouseKeyHook).ToArray());\n        }\n\n        IImageProvider GetImageProvider(RecordingModelParams RecordingParams)\n        {\n            return RecordingParams\n                .VideoSourceKind\n                ?.Source\n                ?.GetImageProvider(Settings.IncludeCursor);\n        }\n\n        public string CurrentFileName { get; private set; }\n        public bool IsVideo { get; private set; }\n\n        public async Task StopRecording()\n        {\n            // Reference Recorder as it will be set to null\n            var rec = _recorder;\n\n            var task = Task.Run(() => rec.Dispose());\n\n            AfterRecording();\n\n            await task;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/ViewModels/RecordingModelParams.cs",
    "content": "﻿using Captura.Audio;\nusing Captura.Video;\n\nnamespace Captura.ViewModels\n{\n    public class RecordingModelParams\n    {\n        public IVideoSourceProvider VideoSourceKind { get; set; }\n\n        public IVideoWriterItem VideoWriter { get; set; }\n\n        public IAudioItem Speaker { get; set; }\n\n        public IAudioItem Microphone { get; set; }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/ViewModels/ScreenShotModel.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Captura.Audio;\nusing Captura.Loc;\nusing Captura.Models;\nusing Captura.Video;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ScreenShotModel : NotifyPropertyChanged\n    {\n        readonly ISystemTray _systemTray;\n        readonly IMainWindow _mainWindow;\n        readonly IVideoSourcePicker _sourcePicker;\n        readonly IAudioPlayer _audioPlayer;\n        readonly Settings _settings;\n        readonly ILocalizationProvider _loc;\n        readonly IPlatformServices _platformServices;\n\n        public IReadOnlyList<IImageWriterItem> AvailableImageWriters { get; }\n\n        public ScreenShotModel(ISystemTray SystemTray,\n            IMainWindow MainWindow,\n            IVideoSourcePicker SourcePicker,\n            IAudioPlayer AudioPlayer,\n            IEnumerable<IImageWriterItem> ImageWriters,\n            Settings Settings,\n            ILocalizationProvider Loc,\n            IPlatformServices PlatformServices)\n        {\n            _systemTray = SystemTray;\n            _mainWindow = MainWindow;\n            _sourcePicker = SourcePicker;\n            _audioPlayer = AudioPlayer;\n            _settings = Settings;\n            _loc = Loc;\n            _platformServices = PlatformServices;\n\n            AvailableImageWriters = ImageWriters.ToList();\n\n            if (!AvailableImageWriters.Any(M => M.Active))\n                AvailableImageWriters[0].Active = true;\n        }\n\n        public async Task ScreenshotRegion()\n        {\n            var region = _sourcePicker.PickRegion();\n\n            if (region == null)\n                return;\n\n            await SaveScreenShot(ScreenShot.Capture(region.Value));\n        }\n\n        public async Task ScreenshotWindow()\n        {\n            var window = _sourcePicker.PickWindow();\n\n            if (window != null)\n            {\n                var img = ScreenShotWindow(window);\n\n                await SaveScreenShot(img);\n            }\n        }\n\n        public async Task ScreenshotScreen()\n        {\n            var screen = _sourcePicker.PickScreen();\n\n            if (screen != null)\n            {\n                var img = ScreenShot.Capture(screen.Rectangle);\n\n                await SaveScreenShot(img);\n            }\n        }\n\n        public async Task SaveScreenShot(IBitmapImage Bmp, string FileName = null)\n        {\n            _audioPlayer.Play(SoundKind.Shot);\n\n            if (Bmp != null)\n            {\n                var allTasks = AvailableImageWriters\n                    .Where(M => M.Active)\n                    .Select(M => M.Save(Bmp, _settings.ScreenShots.ImageFormat, FileName));\n\n                await Task.WhenAll(allTasks).ContinueWith(T => Bmp.Dispose());\n            }\n            else _systemTray.ShowNotification(new TextNotification(_loc.ImgEmpty));\n        }\n\n        public IBitmapImage ScreenShotWindow(IWindow Window)\n        {\n            _systemTray.HideNotification();\n\n            if (Window.Handle == _platformServices.DesktopWindow.Handle)\n            {\n                return ScreenShot.Capture(_settings.IncludeCursor);\n            }\n\n            try\n            {\n                IBitmapImage bmp = null;\n\n                if (_settings.ScreenShots.WindowShotTransparent)\n                {\n                    bmp = ScreenShot.CaptureTransparent(Window, _settings.IncludeCursor);\n                }\n\n                // Capture without Transparency\n                return bmp ?? ScreenShot.Capture(Window.Rectangle, _settings.IncludeCursor);\n            }\n            catch\n            {\n                return null;\n            }\n        }\n\n        public async Task<IBitmapImage> GetScreenShot(IVideoSourceProvider VideoSourceKind, bool SuppressHide = false)\n        {\n            _systemTray.HideNotification();\n\n            // Wait for notifications to hide\n            await Task.Delay(100);\n\n            var includeCursor = _settings.IncludeCursor;\n\n            IBitmapImage bmp;\n\n            switch (VideoSourceKind)\n            {\n                case WindowSourceProvider winProvider when winProvider.Source is WindowItem windowItem:\n                    bmp = ScreenShotWindow(windowItem.Window);\n                    break;\n\n                case FullScreenSourceProvider _:\n                    var hide = !SuppressHide && _mainWindow.IsVisible && _settings.UI.HideOnFullScreenShot;\n\n                    if (hide)\n                    {\n                        _mainWindow.IsVisible = false;\n\n                        // Ensure that the Window is hidden\n                        await Task.Delay(300);\n                    }\n\n                    bmp = VideoSourceKind.Capture(includeCursor);\n\n                    if (hide)\n                        _mainWindow.IsVisible = true;\n                    break;\n\n                default:\n                    bmp = VideoSourceKind.Capture(includeCursor);\n                    break;\n            }\n\n            return bmp;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/ViewModels/TimerModel.cs",
    "content": "﻿using System;\nusing System.Timers;\nusing Captura.Models;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class TimerModel : NotifyPropertyChanged\n    {\n        readonly Settings _settings;\n\n        Timer _timer;\n        readonly Timing _timing = new Timing();\n\n        TimeSpan _ts;\n\n        public TimeSpan TimeSpan\n        {\n            get => _ts;\n            private set => Set(ref _ts, value);\n        }\n\n        int _countdown;\n\n        public int Countdown\n        {\n            get => _countdown;\n            set => Set(ref _countdown, value);\n        }\n\n        bool _waiting;\n\n        public bool Waiting\n        {\n            get => _waiting;\n            set => Set(ref _waiting, value);\n        }\n\n        public TimerModel(Settings Settings)\n        {\n            _settings = Settings;\n        }\n\n        void TimerOnElapsed(object Sender, ElapsedEventArgs Args)\n        {\n            if (Countdown > 0)\n            {\n                if (_timing.Elapsed.TotalSeconds > 1)\n                {\n                    _timing.Stop();\n\n                    --Countdown;\n\n                    _timing.Start();\n                }\n\n                return;\n            }\n\n            if (Waiting)\n            {\n                Waiting = false;\n\n                CountdownElapsed?.Invoke();\n            }\n\n            TimeSpan = TimeSpan.FromSeconds((int)_timing.Elapsed.TotalSeconds);\n\n            var duration = _settings.Duration;\n\n            // If Capture Duration is set and reached\n            if (duration > 0 && TimeSpan.TotalSeconds >= duration)\n            {\n                DurationElapsed?.Invoke();\n            }\n        }\n\n        public event Action CountdownElapsed;\n\n        public event Action DurationElapsed;\n\n        public void Init()\n        {\n            _timer = new Timer(250);\n            _timer.Elapsed += TimerOnElapsed;\n        }\n\n        public void Start()\n        {\n            _timer?.Stop();\n            TimeSpan = TimeSpan.Zero;\n\n            Waiting = false;\n\n            if (_settings.PreStartCountdown > 0)\n            {\n                Countdown = _settings.PreStartCountdown;\n\n                Waiting = true;\n            }\n\n            _timing?.Start();\n            _timer?.Start();\n        }\n\n        public void Pause()\n        {\n            _timer?.Stop();\n            _timing?.Pause();\n        }\n\n        public void Resume()\n        {\n            _timing?.Start();\n            _timer?.Start();\n        }\n\n        public void Stop()\n        {\n            _timer?.Stop();\n            _timing.Stop();\n\n            Countdown = 0;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/ViewModels/ViewModelBase.cs",
    "content": "using Captura.Loc;\n\nnamespace Captura.ViewModels\n{\n    public abstract class ViewModelBase : NotifyPropertyChanged\n    {\n        protected ViewModelBase(Settings Settings, ILocalizationProvider Loc)\n        {\n            this.Settings = Settings;\n            this.Loc = Loc;\n        }\n\n        public Settings Settings { get; }\n\n        public ILocalizationProvider Loc { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/ViewModels/WebcamModel.cs",
    "content": "﻿using System;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing System.Windows.Input;\nusing Captura.Models;\nusing Reactive.Bindings;\n\nnamespace Captura.Webcam\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class WebcamModel : NotifyPropertyChanged\n    {\n        readonly IWebCamProvider _webcamProvider;\n\n        readonly SyncContextManager _syncContext = new SyncContextManager();\n\n        public WebcamModel(IWebCamProvider WebcamProvider)\n        {\n            _webcamProvider = WebcamProvider;\n\n            AvailableCams = new ReadOnlyObservableCollection<IWebcamItem>(_cams);\n\n            RefreshCommand = new DelegateCommand(Refresh);\n\n            Refresh();\n        }\n\n        readonly ObservableCollection<IWebcamItem> _cams = new ObservableCollection<IWebcamItem>();\n\n        public ReadOnlyObservableCollection<IWebcamItem> AvailableCams { get; }\n\n        public void Refresh()\n        {\n            var lastWebcamName = SelectedCam?.Name;\n\n            _cams.Clear();\n\n            _cams.Add(NoWebcamItem.Instance);\n\n            foreach (var cam in _webcamProvider.GetSources())\n                _cams.Add(cam);\n\n            var matchingWebcam = AvailableCams.FirstOrDefault(M => M.Name == lastWebcamName);\n\n            SelectedCam = matchingWebcam ?? NoWebcamItem.Instance;\n        }\n\n        IWebcamItem _selectedCam = NoWebcamItem.Instance;\n\n        public ICommand RefreshCommand { get; }\n\n        public IWebcamItem SelectedCam\n        {\n            get => _selectedCam;\n            set\n            {\n                if (_selectedCam == value)\n                    return;\n\n                ReleaseCaptureInternal();\n\n                _selectedCam = value;\n\n                if (_acquireCount.Value > 0)\n                {\n                    InitCaptureInternal();\n                }\n\n                OnPropertyChanged();\n            }\n        }\n\n        readonly ReactivePropertySlim<IWebcamCapture> _webcamCapture = new ReactivePropertySlim<IWebcamCapture>();\n\n        readonly IReactiveProperty<int> _acquireCount = new ReactivePropertySlim<int>();\n\n        public IReadOnlyReactiveProperty<IWebcamCapture> InitCapture()\n        {\n            ++_acquireCount.Value;\n\n            if (_acquireCount.Value == 1)\n            {\n                InitCaptureInternal();\n            }\n\n            return _webcamCapture;\n        }\n\n        void InitCaptureInternal()\n        {\n            _syncContext.Run(() => _webcamCapture.Value = SelectedCam?.BeginCapture(() => PreviewClicked?.Invoke()));\n        }\n\n        void ReleaseCaptureInternal()\n        {\n            _syncContext.Run(() =>\n            {\n                _webcamCapture.Value?.Dispose();\n                _webcamCapture.Value = null;\n            });\n        }\n\n        public void ReleaseCapture()\n        {\n            --_acquireCount.Value;\n\n            if (_acquireCount.Value == 0)\n            {\n                ReleaseCaptureInternal();\n            }\n        }\n\n        public event Action PreviewClicked;\n    }\n}"
  },
  {
    "path": "src/Captura.Core/WebcamImageProvider.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Windows.Gdi;\nusing Reactive.Bindings;\n\nnamespace Captura.Webcam\n{\n    public class WebcamImageProvider : IImageProvider\n    {\n        WebcamModel _webcamModel;\n        IReadOnlyReactiveProperty<IWebcamCapture> _webcamCapture;\n\n        public WebcamImageProvider(WebcamModel WebcamModel)\n        {\n            _webcamModel = WebcamModel;\n            _webcamCapture = WebcamModel.InitCapture();\n        }\n\n        public void Dispose()\n        {\n            _webcamModel?.ReleaseCapture();\n            _webcamModel = null;\n            _webcamCapture = null;\n        }\n\n        public IEditableFrame Capture()\n        {\n            try\n            {\n                var img = _webcamCapture.Value?.Capture(GraphicsBitmapLoader.Instance);\n\n                if (img is DrawingImage drawingImage && drawingImage.Image is Bitmap bmp)\n                    return new GraphicsEditor(bmp);\n\n                return RepeatFrame.Instance;\n            }\n            catch\n            {\n                return RepeatFrame.Instance;\n            }\n        }\n\n        public IBitmapFrame DummyFrame => DrawingFrame.DummyFrame;\n\n        public int Height => _webcamCapture.Value?.Height ?? 0;\n\n        public int Width => _webcamCapture.Value?.Width ?? 0;\n\n        public Func<Point, Point> PointTransform { get; } = P => P;\n    }\n}"
  },
  {
    "path": "src/Captura.Core/WebcamOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Video;\nusing Reactive.Bindings;\n\nnamespace Captura.Webcam\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class WebcamOverlay : ImageOverlay\n    {\n        WebcamModel _webcamModel;\n        IReadOnlyReactiveProperty<IWebcamCapture> _webcamCapture;\n        readonly WebcamOverlaySettings _settings;\n\n        public WebcamOverlay(WebcamModel WebcamModel, Settings Settings) : base(true)\n        {\n            _webcamModel = WebcamModel;\n            _settings = Settings.WebcamOverlay;\n\n            _webcamCapture = WebcamModel.InitCapture();\n        }\n\n        public override void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null)\n        {\n            // No Webcam\n            if (_webcamModel.AvailableCams.Count < 1 || _webcamModel.SelectedCam is NoWebcamItem)\n                return;\n\n            var cap = _webcamCapture.Value;\n\n            if (cap == null)\n                return;\n\n            var frameSize = new Size((int) Editor.Width, (int) Editor.Height);\n            var webcamSize = new Size(cap.Width, cap.Height);\n\n            var pos = _settings.GetPosition(frameSize, webcamSize);\n            var size = _settings.GetSize(frameSize, webcamSize);\n\n            Draw(Editor, GetImage(Editor), pos, size, _settings.Opacity);\n        }\n\n        IBitmapImage GetImage(IEditableFrame Editor)\n        {\n            return _webcamCapture.Value?.Capture(Editor);\n        }\n\n        public override void Dispose()\n        {\n            base.Dispose();\n\n            _webcamModel?.ReleaseCapture();\n            _webcamModel = null;\n            _webcamCapture = null;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Core/WithPreviewWriter.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace Captura.Video\n{\n    public class WithPreviewWriter : IVideoFileWriter\n    {\n        readonly IPreviewWindow _preview;\n        public IVideoFileWriter OriginalWriter { get; private set; }\n\n        public WithPreviewWriter(IVideoFileWriter Writer, IPreviewWindow Preview)\n        {\n            OriginalWriter = Writer;\n            _preview = Preview;\n        }\n\n        public void Dispose()\n        {\n            OriginalWriter.Dispose();\n            OriginalWriter = null;\n            _preview.Dispose();\n        }\n\n        public void WriteFrame(IBitmapFrame Image)\n        {\n            if (Image is RepeatFrame)\n            {\n                OriginalWriter.WriteFrame(Image);\n            }\n            else\n            {\n                var frame = new MultiDisposeFrame(Image, 2);\n\n                OriginalWriter.WriteFrame(frame);\n                Task.Run(() => _preview.Display(frame));\n            }\n        }\n\n        public bool SupportsAudio => OriginalWriter.SupportsAudio;\n\n        public void WriteAudio(byte[] Buffer, int Offset, int Length)\n        {\n            OriginalWriter.WriteAudio(Buffer, Offset, Length);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/ArgsBuilder/FFmpegArgs.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Captura.FFmpeg\n{\n    public abstract class FFmpegArgs\n    {\n        protected readonly List<string> Args = new List<string>();\n\n        public virtual string GetArgs()\n        {\n            return string.Join(\" \", Args);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/ArgsBuilder/FFmpegArgsBuilder.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Captura.FFmpeg\n{\n    public class FFmpegArgsBuilder\n    {\n        readonly List<FFmpegInputArgs> _inputs = new List<FFmpegInputArgs>();\n        readonly List<FFmpegOutputArgs> _outputs = new List<FFmpegOutputArgs>();\n\n        const string PipePrefix = @\"\\\\.\\pipe\\\";\n\n        public FFmpegInputArgs AddInputFile(string FileName)\n        {\n            var input = new FFmpegInputArgs($\"\\\"{FileName}\\\"\");\n\n            _inputs.Add(input);\n\n            return input;\n        }\n\n        public FFmpegInputArgs AddStdIn()\n        {\n            var input = new FFmpegInputArgs(\"-\");\n\n            _inputs.Add(input);\n\n            return input;\n        }\n\n        public FFmpegInputArgs AddInputPipe(string NamedPipe)\n        {\n            var input = new FFmpegInputArgs($\"{PipePrefix}{NamedPipe}\");\n\n            _inputs.Add(input);\n\n            return input;\n        }\n\n        public FFmpegOutputArgs AddOutputFile(string FileName)\n        {\n            var output = new FFmpegOutputArgs($\"\\\"{FileName}\\\"\");\n\n            _outputs.Add(output);\n\n            return output;\n        }\n\n        public FFmpegOutputArgs AddStdOut()\n        {\n            var output = new FFmpegOutputArgs(\"-\");\n\n            _outputs.Add(output);\n\n            return output;\n        }\n\n        public FFmpegOutputArgs AddOutputPipe(string NamedPipe)\n        {\n            var output = new FFmpegOutputArgs($\"{PipePrefix}{NamedPipe}\");\n\n            _outputs.Add(output);\n\n            return output;\n        }\n\n        public string GetArgs()\n        {\n            var args = new List<string>();\n\n            foreach (var input in _inputs)\n            {\n                args.Add(input.GetArgs());\n            }\n\n            foreach (var output in _outputs)\n            {\n                args.Add(output.GetArgs());\n            }\n\n            return string.Join(\" \", args);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/ArgsBuilder/FFmpegInputArgs.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    public class FFmpegInputArgs : FFmpegArgs\n    {\n        readonly string _input;\n\n        public FFmpegInputArgs(string Input)\n        {\n            _input = Input;\n        }\n\n        public override string GetArgs()\n        {\n            return base.GetArgs() + $\" -i {_input}\";\n        }\n\n        public FFmpegInputArgs AddArg(string Arg)\n        {\n            Args.Add(Arg);\n\n            return this;\n        }\n\n        public FFmpegInputArgs AddArg<T>(string Key, T Value)\n        {\n            return AddArg($\"-{Key} {Value}\");\n        }\n\n        public FFmpegInputArgs SetVideoSize(int Width, int Height)\n        {\n            return AddArg(\"video_size\", $\"{Width}x{Height}\");\n        }\n\n        public FFmpegInputArgs SetFrameRate(int FrameRate)\n        {\n            return AddArg(\"r\", FrameRate);\n        }\n\n        public FFmpegInputArgs SetFormat(string Format)\n        {\n            return AddArg(\"f\", Format);\n        }\n\n        public FFmpegInputArgs SetAudioCodec(string Codec)\n        {\n            return AddArg(\"acodec\", Codec);\n        }\n\n        public FFmpegInputArgs SetAudioFrequency(int Frequency)\n        {\n            return AddArg(\"ar\", Frequency);\n        }\n\n        public FFmpegInputArgs SetAudioChannels(int Channels)\n        {\n            return AddArg(\"ac\", Channels);\n        }\n\n        public FFmpegInputArgs DisableVideo()\n        {\n            return AddArg(\"-vn\");\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/ArgsBuilder/FFmpegOutputArgs.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    public class FFmpegOutputArgs : FFmpegArgs\n    {\n        string _output;\n\n        public FFmpegOutputArgs(string Output)\n        {\n            _output = Output;\n        }\n\n        public void UpdateOutput(string Output)\n        {\n            _output = Output;\n        }\n\n        public override string GetArgs()\n        {\n            return base.GetArgs() + $\" {_output}\";\n        }\n\n        public FFmpegOutputArgs AddArg(string Arg)\n        {\n            Args.Add(Arg);\n\n            return this;\n        }\n\n        public FFmpegOutputArgs AddArg<T>(string Key, T Value)\n        {\n            return AddArg($\"-{Key} {Value}\");\n        }\n\n        public FFmpegOutputArgs SetVideoSize(int Width, int Height)\n        {\n            return AddArg(\"video_size\", $\"{Width}x{Height}\");\n        }\n\n        public FFmpegOutputArgs SetFrameRate(int FrameRate)\n        {\n            return AddArg(\"r\", FrameRate);\n        }\n\n        public FFmpegOutputArgs SetAudioCodec(string Codec)\n        {\n            return AddArg(\"c:a\", Codec);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Audio/FFmpegAudioArgsProvider.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    /// <summary>\n    /// Provides FFmpeg Audio encoding Command-line args.\n    /// </summary>\n    public delegate void FFmpegAudioArgsProvider(int AudioQuality, FFmpegOutputArgs OutputArgs);\n}\n"
  },
  {
    "path": "src/Captura.FFmpeg/Audio/FFmpegAudioItem.cs",
    "content": "﻿using System.Collections.Generic;\nusing Captura.Audio;\n\nnamespace Captura.FFmpeg\n{\n    public class FFmpegAudioItem : IAudioWriterItem\n    {\n        public FFmpegAudioArgsProvider AudioArgsProvider { get; }\n\n        const string Experimental = \"-strict -2\";\n\n        FFmpegAudioItem(string Name, string Extension, FFmpegAudioArgsProvider AudioArgsProvider)\n        {\n            this.Name = Name;\n            this.Extension = Extension;\n\n            this.AudioArgsProvider = AudioArgsProvider;\n        }\n\n        public string Name { get; }\n\n        string IAudioWriterItem.Name => $\"{Name} (FFmpeg)\";\n\n        public string Extension { get; }\n\n        public override string ToString() => Name;\n\n        public IAudioFileWriter GetAudioFileWriter(string FileName, WaveFormat Wf, int AudioQuality)\n        {\n            return new FFmpegAudioWriter(FileName, AudioQuality, AudioArgsProvider, Wf.SampleRate, Wf.Channels);\n        }\n\n        public static FFmpegAudioArgsProvider Aac { get; } = (Quality, OutputArgs) =>\n        {\n            // bitrate: 32k to 512k (steps of 32k)\n            var b = 32 * (1 + (15 * (Quality - 1)) / 99);\n\n            OutputArgs.SetAudioCodec(\"aac\")\n                .AddArg(Experimental)\n                .AddArg(\"b:a\", $\"{b}k\");\n        };\n\n        public static FFmpegAudioArgsProvider Mp3 { get; } = (Quality, OutputArgs) =>\n        {\n            // quality: 9 (lowest) to 0 (highest)\n            var qscale = (100 - Quality) / 11;\n\n            OutputArgs.SetAudioCodec(\"libmp3lame\")\n                .AddArg(\"qscale:a\", qscale);\n        };\n\n        public static FFmpegAudioArgsProvider Vorbis { get; } = (Quality, OutputArgs) =>\n        {\n            // quality: 0 (lowest) to 10 (highest)\n            var qscale = (10 * (Quality - 1)) / 99;\n\n            OutputArgs.SetAudioCodec(\"libvorbis\")\n                .AddArg(\"qscale:a\", qscale);\n        };\n\n        public static FFmpegAudioArgsProvider Opus { get; } = (Quality, OutputArgs) =>\n        {\n            // quality: 0 (lowest) to 10 (highest)\n            var qscale = (10 * (Quality - 1)) / 99;\n\n            OutputArgs.SetAudioCodec(\"libopus\")\n                .AddArg(\"compression_level\", qscale);\n        };\n\n        public static IEnumerable<FFmpegAudioItem> Items { get; } = new[]\n        {\n            new FFmpegAudioItem(\"AAC\", \".aac\", Aac),\n            new FFmpegAudioItem(\"Mp3\", \".mp3\", Mp3),\n            new FFmpegAudioItem(\"Vorbis\", \".ogg\", Vorbis),\n            new FFmpegAudioItem(\"Opus\", \".opus\", Opus)\n        };\n    }\n}\n"
  },
  {
    "path": "src/Captura.FFmpeg/Audio/FFmpegAudioWriter.cs",
    "content": "﻿using Captura.Audio;\nusing System.Diagnostics;\nusing System.IO;\n\nnamespace Captura.FFmpeg\n{\n    class FFmpegAudioWriter : IAudioFileWriter\n    {\n        readonly Process _ffmpegProcess;\n        readonly Stream _ffmpegIn;\n        \n        public FFmpegAudioWriter(string FileName, int AudioQuality, FFmpegAudioArgsProvider AudioArgsProvider, int Frequency = 44100, int Channels = 2)\n        {\n            if (!FFmpegService.FFmpegExists)\n            {\n                throw new FFmpegNotFoundException();\n            }\n\n            var argsBuilder  = new FFmpegArgsBuilder();\n\n            argsBuilder.AddStdIn()\n                .SetFormat(\"s16le\")\n                .SetAudioCodec(\"pcm_s16le\")\n                .SetAudioFrequency(Frequency)\n                .SetAudioChannels(Channels)\n                .DisableVideo();\n\n            var output = argsBuilder.AddOutputFile(FileName);\n\n            AudioArgsProvider(AudioQuality, output);\n\n            _ffmpegProcess = FFmpegService.StartFFmpeg(argsBuilder.GetArgs(), FileName, out _);\n            \n            _ffmpegIn = _ffmpegProcess.StandardInput.BaseStream;\n        }\n\n        public void Dispose()\n        {\n            Flush();\n\n            _ffmpegIn.Close();\n            _ffmpegProcess.WaitForExit();\n        }\n\n        public void Flush()\n        {\n            _ffmpegIn.Flush();\n        }\n\n        public void Write(byte[] Data, int Offset, int Count)\n        {\n            if (_ffmpegProcess.HasExited)\n            {\n                throw new FFmpegException(_ffmpegProcess.ExitCode);\n            }\n\n            _ffmpegIn.Write(Data, Offset, Count);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.FFmpeg/Captura.FFmpeg.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Loc\\Captura.Loc.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Captura.FFmpeg/DownloadFFmpeg.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.IO.Compression;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Captura.FFmpeg\n{\n    public static class DownloadFFmpeg\n    {\n        static readonly Uri FFmpegUri;\n        static readonly string FFmpegArchivePath;\n\n        static DownloadFFmpeg()\n        {\n            var bits = Environment.Is64BitOperatingSystem ? 64 : 32;\n\n            FFmpegUri = new Uri($\"https://ffmpeg.zeranoe.com/builds/win{bits}/static/ffmpeg-latest-win{bits}-static.zip\");\n\n            FFmpegArchivePath = Path.Combine(Path.GetTempPath(), \"ffmpeg.zip\");\n        }\n\n        public static async Task DownloadArchive(Action<int> Progress, IWebProxy Proxy, CancellationToken CancellationToken)\n        {\n            using var webClient = new WebClient { Proxy = Proxy };\n            CancellationToken.Register(() => webClient.CancelAsync());\n\n            webClient.DownloadProgressChanged += (S, E) =>\n            {\n                Progress?.Invoke(E.ProgressPercentage);\n            };\n                \n            await webClient.DownloadFileTaskAsync(FFmpegUri, FFmpegArchivePath);\n        }\n\n        const string ExeName = \"ffmpeg.exe\";\n\n        public static async Task ExtractTo(string FolderPath)\n        {\n            await Task.Run(() =>\n            {\n                using var archive = ZipFile.OpenRead(FFmpegArchivePath);\n                var ffmpegEntry = archive.Entries.First(M => M.Name == ExeName);\n\n                ffmpegEntry.ExtractToFile(Path.Combine(FolderPath, ExeName), true);\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/FFMpegLogItem.cs",
    "content": "﻿using System;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace Captura.FFmpeg\n{\n    public class FFmpegLogItem : NotifyPropertyChanged, IFFmpegLogEntry\n    {\n        public string Name { get; }\n\n        public string Args { get; }\n\n        public FFmpegLogItem(string Name, string Args)\n        {\n            this.Name = Name;\n            this.Args = Args;\n\n            _complete.AppendLine(\"ARGS:\");\n            _complete.AppendLine(\"-------------\");\n            _complete.AppendLine(Args);\n            _complete.AppendLine();\n            _complete.AppendLine(\"OUTPUT:\");\n            _complete.AppendLine(\"-------------\");\n        }\n\n        string _content = \"\", _frame = \"\";\n\n        readonly StringBuilder _complete = new StringBuilder();\n\n        public event Action<int> ProgressChanged;\n\n        TimeSpan? _duration;\n        int _lastReportedProgress;\n\n        readonly Regex _durationRegex = new Regex(@\"Duration: (\\d{2}:\\d{2}:\\d{2}.\\d{2})\");\n        readonly Regex _timeRegex = new Regex(@\"time=(\\d{2}:\\d{2}:\\d{2}.\\d{2})\");\n\n        public void Write(string Text)\n        {\n            if (Text == null)\n                return;\n\n            _complete.AppendLine(Text);\n\n            if (_duration == null)\n            {\n                var match = _durationRegex.Match(Text);\n\n                if (match.Success)\n                {\n                    _duration = TimeSpan.Parse(match.Groups[1].Value);\n                }\n            }\n\n            if (Text.StartsWith(\"frame=\") || Text.StartsWith(\"size=\"))\n            {\n                Frame = Text;\n\n                if (_duration != null)\n                {\n                    var match = _timeRegex.Match(Text);\n\n                    if (match.Success)\n                    {\n                        var time = TimeSpan.Parse(match.Groups[1].Value);\n\n                        var progress = (int)(time.TotalMilliseconds * 100 / _duration.Value.TotalMilliseconds);\n\n                        if (progress > _lastReportedProgress)\n                        {\n                            _lastReportedProgress = progress;\n                            ProgressChanged?.Invoke(progress);\n                        }\n                    }\n                }\n            }\n            else Content += Text + Environment.NewLine;\n        }\n\n        public string Frame\n        {\n            get => _frame;\n            private set => Set(ref _frame, value);\n        }\n\n        public string Content\n        {\n            get => _content;\n            private set => Set(ref _content, value);\n        }\n\n        public string GetCompleteLog() => _complete.ToString();\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/FFmpegDownloaderProgress.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    public class FFmpegDownloaderProgress\n    {\n        public FFmpegDownloaderProgress(int Progress)\n        {\n            State = FFmpegDownloaderState.Downloading;\n            DownloadProgress = Progress;\n        }\n\n        public FFmpegDownloaderProgress(string ErrorMessage)\n        {\n            State = FFmpegDownloaderState.Error;\n            this.ErrorMessage = ErrorMessage;\n        }\n\n        public FFmpegDownloaderProgress(FFmpegDownloaderState State)\n        {\n            this.State = State;\n        }\n\n        public FFmpegDownloaderState State { get; }\n\n        public int DownloadProgress { get; }\n\n        public string ErrorMessage { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/FFmpegDownloaderState.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    public enum FFmpegDownloaderState\n    {\n        Ready,\n        Downloading,\n        Extracting,\n        Done,\n        Cancelled,\n        Error\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/FFmpegException.cs",
    "content": "﻿using System;\n\nnamespace Captura.FFmpeg\n{\n    public class FFmpegException : Exception\n    {\n        public FFmpegException(int ExitCode, Exception InnerException = null)\n            : base($\"An Error Occurred with FFmpeg, Exit Code: {ExitCode}.\\nSee FFmpeg Log for more info.\", InnerException) { }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/FFmpegModule.cs",
    "content": "﻿using Captura.Audio;\nusing Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    public static class FFmpegModule\n    {\n        public static void Load(IBinder Binder)\n        {\n            Binder.BindSingleton<FFmpegSettings>();\n            Binder.BindAsInterfaceAndClass<IVideoWriterProvider, FFmpegWriterProvider>();\n            Binder.BindAsInterfaceAndClass<IVideoWriterProvider, StreamingWriterProvider>();\n\n            foreach (var audioItem in FFmpegAudioItem.Items)\n            {\n                Binder.Bind<IAudioWriterItem>(() => audioItem);\n            }\n\n            Binder.Bind<IVideoConverter>(() => new FFmpegGifConverter());\n            Binder.Bind<IVideoConverter>(() => new FFmpegVideoConverter(new Vp8VideoCodec()));\n            Binder.Bind<IVideoConverter>(() => new FFmpegVideoConverter(new Vp9VideoCodec()));\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/FFmpegNotFoundException.cs",
    "content": "﻿using System;\n\nnamespace Captura.FFmpeg\n{\n    public class FFmpegNotFoundException : Exception\n    {\n        public override string Message => \"FFmpeg could not be found. Please download using the in-built downloader.\";\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/FFmpegService.cs",
    "content": "﻿using System.Diagnostics;\nusing System.IO;\nusing System.IO.Pipes;\nusing System.Linq;\n\nnamespace Captura.FFmpeg\n{\n    public static class FFmpegService\n    {\n        const string FFmpegExeName = \"ffmpeg.exe\";\n\n        static FFmpegSettings GetSettings() => ServiceProvider.Get<FFmpegSettings>();\n\n        public static bool FFmpegExists\n        {\n            get\n            {\n                var folderPath = GetSettings().GetFolderPath();\n\n                // FFmpeg folder\n                if (!string.IsNullOrWhiteSpace(folderPath))\n                {\n                    var path = Path.Combine(folderPath, FFmpegExeName);\n\n                    if (File.Exists(path))\n                        return true;\n                }\n\n                if (ServiceProvider.FileExists(FFmpegExeName))\n                    return true;\n\n                // PATH\n                try\n                {\n                    Process.Start(new ProcessStartInfo\n                    {\n                        FileName = FFmpegExeName,\n                        Arguments = \"-version\",\n                        UseShellExecute = false,\n                        CreateNoWindow = true\n                    });\n\n                    return true;\n                }\n                catch { return false; }\n            }\n        }\n\n        public static string FFmpegExePath\n        {\n            get\n            {\n                var folderPath = GetSettings().GetFolderPath();\n\n                // FFmpeg folder\n                if (!string.IsNullOrWhiteSpace(folderPath))\n                {\n                    var path = Path.Combine(folderPath, FFmpegExeName);\n\n                    if (File.Exists(path))\n                        return path;\n                }\n\n                return new[] { ServiceProvider.AppDir, ServiceProvider.LibDir }\n                           .Where(M => M != null)\n                           .FirstOrDefault(M => File.Exists(Path.Combine(M, FFmpegExeName)))\n                       ?? FFmpegExeName;\n            }\n        }\n\n        public static Process StartFFmpeg(string Arguments, string FileName, out IFFmpegLogEntry FFmpegLog)\n        {\n            var process = new Process\n            {\n                StartInfo =\n                {\n                    FileName = FFmpegExePath,\n                    Arguments = Arguments,\n                    UseShellExecute = false,\n                    CreateNoWindow = true,\n                    RedirectStandardError = true,\n                    RedirectStandardInput = true\n                },\n                EnableRaisingEvents = true\n            };\n            \n            var log = ServiceProvider.Get<IFFmpegLogRepository>();\n\n            var logItem = log.CreateNew(Path.GetFileName(FileName), Arguments);\n            FFmpegLog = logItem;\n                        \n            process.ErrorDataReceived += (S, E) => logItem.Write(E.Data);\n\n            process.Start();\n\n            process.BeginErrorReadLine();\n            \n            return process;\n        }\n\n        public static bool WaitForConnection(this NamedPipeServerStream ServerStream, int Timeout)\n        {\n            var asyncResult = ServerStream.BeginWaitForConnection(Ar => {}, null);\n\n            if (asyncResult.AsyncWaitHandle.WaitOne(Timeout))\n            {\n                ServerStream.EndWaitForConnection(asyncResult);\n\n                return ServerStream.IsConnected;\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.FFmpeg/FFmpegTrimmer.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\n\nnamespace Captura.FFmpeg\n{\n    public class FFmpegTrimmer\n    {\n        public async Task Run(string SourceFile,\n            TimeSpan From,\n            TimeSpan To,\n            string DestFile,\n            bool HasAudio)\n        {\n            var argsBuilder = new FFmpegArgsBuilder();\n\n            var inputArgs = argsBuilder.AddInputFile(SourceFile)\n                .AddArg(\"ss\", From)\n                .AddArg(\"to\", To);\n\n            if (HasAudio)\n                inputArgs.SetAudioCodec(\"copy\");\n\n            argsBuilder.AddOutputFile(DestFile);\n\n            var args = argsBuilder.GetArgs();\n\n            var process = FFmpegService.StartFFmpeg(args, DestFile, out _);\n\n            await Task.Factory.StartNew(process.WaitForExit);\n\n            if (process.ExitCode != 0)\n            {\n                throw new FFmpegException(process.ExitCode);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/FFmpgDownloadModel.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Captura.Loc;\n\nnamespace Captura.FFmpeg\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FFmpegDownloadModel : NotifyPropertyChanged\n    {\n        readonly ProxySettings _proxySettings;\n        readonly FFmpegSettings _ffmpegSettings;\n\n        public FFmpegDownloadModel(ProxySettings ProxySettings,\n            ILocalizationProvider Loc,\n            FFmpegSettings FFmpegSettings)\n        {\n            _proxySettings = ProxySettings;\n\n            _ffmpegSettings = FFmpegSettings;\n        }\n\n        public async Task<bool> Start(IProgress<FFmpegDownloaderProgress> Progress, CancellationToken CancellationToken)\n        {\n            // First progress report takes some time\n            Progress.Report(new FFmpegDownloaderProgress(0));\n\n            try\n            {\n                var lastProgress = -1;\n\n                await DownloadFFmpeg.DownloadArchive(P =>\n                {\n                    if (lastProgress == P)\n                        return;\n\n                    // Report only if changed\n                    Progress.Report(new FFmpegDownloaderProgress(P));\n\n                    lastProgress = P;\n                }, _proxySettings.GetWebProxy(), CancellationToken);\n            }\n            catch (WebException webException) when(webException.Status == WebExceptionStatus.RequestCanceled)\n            {\n                Progress.Report(new FFmpegDownloaderProgress(FFmpegDownloaderState.Cancelled));\n                return false;\n            }\n            catch (Exception e)\n            {\n                Progress.Report(new FFmpegDownloaderProgress($\"Failed - {e.Message}\"));\n                return false;\n            }\n\n            // Download complete\n            Progress.Report(new FFmpegDownloaderProgress(100));\n\n            Progress.Report(new FFmpegDownloaderProgress(FFmpegDownloaderState.Extracting));\n\n            try\n            {\n                var ffmpegFolder = _ffmpegSettings.GetFolderPath();\n\n                if (!Directory.Exists(ffmpegFolder))\n                {\n                    Directory.CreateDirectory(ffmpegFolder);\n                }\n\n                await DownloadFFmpeg.ExtractTo(ffmpegFolder);\n            }\n            catch (UnauthorizedAccessException)\n            {\n                Progress.Report(new FFmpegDownloaderProgress(\"Can't extract to specified directory\"));\n                return false;\n            }\n            catch\n            {\n                Progress.Report(new FFmpegDownloaderProgress(\"Extraction Failed\"));\n                return false;\n            }\n\n            Progress.Report(new FFmpegDownloaderProgress(FFmpegDownloaderState.Done));\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.FFmpeg/IFFmpegLogEntry.cs",
    "content": "﻿using System;\n\nnamespace Captura.FFmpeg\n{\n    public interface IFFmpegLogEntry\n    {\n        void Write(string Line);\n\n        string GetCompleteLog();\n\n        event Action<int> ProgressChanged;\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/IFFmpegLogRepository.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Captura.FFmpeg\n{\n    public interface IFFmpegLogRepository : IEnumerable<IFFmpegLogEntry>\n    {\n        IFFmpegLogEntry CreateNew(string Name, string Args);\n\n        void Remove(IFFmpegLogEntry Entry);\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/IFFmpegViewsProvider.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    public interface IFFmpegViewsProvider\n    {\n        void ShowLogs();\n\n        void ShowUnavailable();\n\n        void ShowDownloader();\n\n        void PickFolder();\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Settings/FFMpegSettings.cs",
    "content": "﻿using System;\nusing System.Collections.ObjectModel;\nusing System.IO;\n\nnamespace Captura.FFmpeg\n{\n    public class FFmpegSettings : PropertyStore\n    {\n        public string FolderPath\n        {\n            get => Get<string>();\n            set => Set(value);\n        }\n\n        public string GetFolderPath()\n        {\n            var path = FolderPath;\n\n            if (!string.IsNullOrWhiteSpace(path))\n            {\n                return path.Replace(ServiceProvider.CapturaPathConstant,\n                    ServiceProvider.AppDir);\n            }\n\n            var localCodecs = Path.Combine(ServiceProvider.AppDir, \"Codecs\");\n\n            if (Directory.Exists(localCodecs))\n            {\n                path = localCodecs;\n            }\n            else\n            {\n                var localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);\n\n                path = Path.Combine(localAppDataPath, nameof(Captura));\n            }\n\n            return path;\n        }\n\n        public string TwitchKey\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public string YouTubeLiveKey\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public ObservableCollection<FFmpegCodecSettings> CustomCodecs { get; } = new ObservableCollection<FFmpegCodecSettings>();\n\n        public string CustomStreamingUrl\n        {\n            get => Get(\"rtmp://\");\n            set => Set(value);\n        }\n\n        public bool Resize\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n\n        public int ResizeWidth\n        {\n            get => Get(640);\n            set => Set(value);\n        }\n\n        public int ResizeHeight\n        {\n            get => Get(480);\n            set => Set(value);\n        }\n\n        public X264Settings X264 { get; } = new X264Settings();\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Settings/FFmpegCodecSettings.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    public class FFmpegCodecSettings : PropertyStore\n    {\n        public string Name\n        {\n            get => Get(\"Custom\");\n            set => Set(value);\n        }\n\n        public string Args\n        {\n            get => Get(\"-vcodec libx264 -crf 30 -pix_fmt yuv420p -preset ultrafast\");\n            set => Set(value);\n        }\n\n        public string Extension\n        {\n            get => Get(\".mp4\");\n            set => Set(value);\n        }\n\n        public string AudioFormat\n        {\n            get => Get(\"Mp3\");\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Settings/X264Settings.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\n\nnamespace Captura.FFmpeg\n{\n    public class X264Settings : PropertyStore\n    {\n        /// <summary>\n        /// ultrafast is recommended\n        /// </summary>\n        public static IEnumerable<string> Presets { get; } = new[] { \"veryslow\", \"slower\", \"slow\", \"medium\", \"fast\", \"faster\", \"veryfast\", \"superfast\", \"ultrafast\" };\n\n        public string Preset\n        {\n            get => Get(\"ultrafast\");\n            set\n            {\n                if (Presets.Contains(value))\n                {\n                    Set(value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// yuv420p has better compatibility whereas yuv444p has better quality\n        /// </summary>\n        public static IEnumerable<string> PixelFormats { get; } = new[] { \"yuv420p\", \"yuv444p\" };\n\n        public string PixelFormat\n        {\n            get => Get(\"yuv420p\");\n            set\n            {\n                if (PixelFormats.Contains(value))\n                {\n                    Set(value);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/CustomFFmpegVideoCodec.cs",
    "content": "﻿using System.Linq;\nusing Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    class CustomFFmpegVideoCodec : FFmpegVideoCodec\n    {\n        readonly FFmpegCodecSettings _codecSettings;\n\n        public CustomFFmpegVideoCodec(FFmpegCodecSettings CodecSettings)\n            : base(\"\", \"\", \"Custom Codec\")\n        {\n            _codecSettings = CodecSettings;\n        }\n\n        public override string Name => _codecSettings.Name;\n\n        public override string Extension => _codecSettings.Extension;\n\n        public override FFmpegAudioArgsProvider AudioArgsProvider => FFmpegAudioItem.Items\n                                                                         .FirstOrDefault(M => M.Name == _codecSettings.AudioFormat)\n                                                                         ?.AudioArgsProvider ?? FFmpegAudioItem.Mp3;\n\n        public override void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs)\n        {\n            OutputArgs.AddArg(_codecSettings.Args);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/CustomStreamingVideoCodec.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    class CustomStreamingVideoCodec : StreamingVideoCodec\n    {\n        public CustomStreamingVideoCodec() : base(\"Custom\", \"Stream to custom service\") { }\n\n        protected override string GetLink(FFmpegSettings Settings)\n        {\n            return Settings.CustomStreamingUrl;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/FFmpegVideoCodec.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    abstract class FFmpegVideoCodec : IVideoWriterItem\n    {\n        protected FFmpegVideoCodec(string Name, string Extension, string Description)\n        {\n            this.Name = Name;\n            this.Extension = Extension;\n            this.Description = Description;\n        }\n\n        public virtual string Name { get; }\n\n        public virtual string Extension { get; }\n\n        public string Description { get; }\n\n        public abstract FFmpegAudioArgsProvider AudioArgsProvider { get; }\n\n        public abstract void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs);\n\n        public virtual IVideoFileWriter GetVideoFileWriter(VideoWriterArgs Args)\n        {\n            return new FFmpegWriter(FFmpegVideoWriterArgs.FromVideoWriterArgs(Args, this));\n        }\n\n        public override string ToString() => Name;\n    }\n}\n"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/NvencVideoCodec.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    class NvencVideoCodec : FFmpegVideoCodec\n    {\n        readonly string _fFmpegCodecName;\n\n        const string NVencSupport = \"If this doesn't work, please check on NVIDIA's website whether your graphic card supports NVenc.\";\n\n        NvencVideoCodec(string Name, string FFmpegCodecName, string Description)\n            : base(Name, \".mp4\", $\"{Description}\\n{NVencSupport}\")\n        {\n            _fFmpegCodecName = FFmpegCodecName;\n        }\n\n        public override FFmpegAudioArgsProvider AudioArgsProvider => FFmpegAudioItem.Aac;\n\n        public override void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs)\n        {\n            OutputArgs.AddArg(\"c:v\", _fFmpegCodecName)\n                .AddArg(\"pixel_format\", \"yuv444p\")\n                .AddArg(\"preset\", \"fast\");\n        }\n\n        public static NvencVideoCodec CreateH264()\n        {\n            return new NvencVideoCodec(\"NVenc: Mp4 (H.264, AAC)\", \"h264_nvenc\", \"Encode to Mp4: H.264 with AAC audio using NVenc\");\n        }\n\n        public static NvencVideoCodec CreateHevc()\n        {\n            return new NvencVideoCodec(\"NVenc: Mp4 (HEVC, AAC)\", \"hevc_nvenc\", \"Encode to Mp4: HEVC with AAC audio using NVenc\");\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/QsvHevcVideoCodec.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    class QsvHevcVideoCodec : FFmpegVideoCodec\n    {\n        const string Descr = \"Encode to Mp4: HEVC (H.265) with AAC audio using Intel QuickSync hardware encoding.\\nRequires the processor to be Skylake generation or later\";\n\n        public QsvHevcVideoCodec() : base(\"Intel QuickSync: Mp4 (HEVC, AAC)\", \".mp4\", Descr) { }\n\n        public override FFmpegAudioArgsProvider AudioArgsProvider => FFmpegAudioItem.Aac;\n\n        public override void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs)\n        {\n            OutputArgs.AddArg(\"vcodec\", \"hevc_qsv\")\n                .AddArg(\"load_plugin\", \"hevc_hw\")\n                .AddArg(\"q\", 2)\n                .AddArg(\"preset:v\", \"veryfast\");\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/StreamingVideoCodec.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    abstract class StreamingVideoCodec : FFmpegVideoCodec\n    {\n        protected StreamingVideoCodec(string Name, string Description) : base(Name, \".mp4\", Description) { }\n\n        public override void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs)\n        {\n            var x264 = new X264VideoCodec();\n\n            x264.Apply(Settings, WriterArgs, OutputArgs);\n\n            OutputArgs.AddArg(\"g\", WriterArgs.FrameRate * 2)\n                .AddArg(\"r\", WriterArgs.FrameRate)\n                .AddArg(\"f\", \"flv\");\n\n            var link = GetLink(Settings);\n\n            WriterArgs.FileName = link;\n            OutputArgs.UpdateOutput(link);\n        }\n\n        protected abstract string GetLink(FFmpegSettings Settings);\n\n        public override FFmpegAudioArgsProvider AudioArgsProvider => FFmpegAudioItem.Mp3;\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/TempFileVideoCodec.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    class TempFileVideoCodec : X264VideoCodec\n    {\n        public override void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs)\n        {\n            base.Apply(Settings, WriterArgs, OutputArgs);\n\n            OutputArgs.AddArg(\"f\", \"mp4\")\n                .AddArg(\"-y\");\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/TwitchVideoCodec.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    class TwitchVideoCodec : StreamingVideoCodec\n    {\n        public TwitchVideoCodec() : base(\"Twitch\", \"Stream to Twitch\") { }\n\n        protected override string GetLink(FFmpegSettings Settings)\n        {\n            return $\"rtmp://live.twitch.tv/app/{Settings.TwitchKey}\";\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/Vp8VideoCodec.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    class Vp8VideoCodec : FFmpegVideoCodec\n    {\n        const string Descr = \"Encode to WebM: Vp8 with Opus audio\";\n\n        public Vp8VideoCodec() : base(\"WebM (Vp8, Opus)\", \".webm\", Descr) { }\n\n        public override FFmpegAudioArgsProvider AudioArgsProvider => FFmpegAudioItem.Opus;\n\n        public override void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs)\n        {\n            // quality: 63 (lowest) to 4 (highest)\n            var crf = 63 - ((WriterArgs.VideoQuality - 1) * 59) / 99;\n\n            OutputArgs.AddArg(\"vcodec\", \"libvpx\")\n                .AddArg(\"crf\", crf)\n                .AddArg(\"b:v\", \"1M\");\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/Vp9VideoCodec.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    class Vp9VideoCodec : FFmpegVideoCodec\n    {\n        const string Descr = \"Encode to WebM: Vp9 with Opus audio\";\n\n        public Vp9VideoCodec() : base(\"WebM (Vp9, Opus)\", \".webm\", Descr) { }\n\n        public override FFmpegAudioArgsProvider AudioArgsProvider => FFmpegAudioItem.Opus;\n\n        public override void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs)\n        {\n            // quality: 63 (lowest) to 0 (highest)\n            var crf = (63 * (100 - WriterArgs.VideoQuality)) / 99;\n\n            OutputArgs.AddArg(\"vcodec\", \"libvpx-vp9\")\n                .AddArg(\"crf\", crf)\n                .AddArg(\"b:v\", 0);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/X264VideoCodec.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    class X264VideoCodec : FFmpegVideoCodec\n    {\n        const string Descr = \"Encode to Mp4: H.264 with AAC audio using x264 encoder.\";\n\n        public X264VideoCodec() : base(\"Mp4 (H.264, AAC)\", \".mp4\", Descr) { }\n\n        public override FFmpegAudioArgsProvider AudioArgsProvider => FFmpegAudioItem.Aac;\n\n        public override void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs)\n        {\n            // quality: 51 (lowest) to 0 (highest)\n            var crf = (51 * (100 - WriterArgs.VideoQuality)) / 99;\n\n            OutputArgs.AddArg(\"vcodec\", \"libx264\")\n                .AddArg(\"crf\", crf)\n                .AddArg(\"pix_fmt\", Settings.X264.PixelFormat)\n                .AddArg(\"preset\", Settings.X264.Preset);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/XvidVideoCodec.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    class XvidVideoCodec : FFmpegVideoCodec\n    {\n        const string Descr = \"Encode to Avi with Mp3 audio using Xvid encoder\";\n\n        public XvidVideoCodec() : base(\"Avi (Xvid, Mp3)\", \".avi\", Descr) { }\n\n        public override FFmpegAudioArgsProvider AudioArgsProvider => FFmpegAudioItem.Mp3;\n\n        public override void Apply(FFmpegSettings Settings, VideoWriterArgs WriterArgs, FFmpegOutputArgs OutputArgs)\n        {\n            // quality: 31 (lowest) to 1 (highest)\n            var qscale = 31 - ((WriterArgs.VideoQuality - 1) * 30) / 99;\n\n            OutputArgs.AddArg(\"vcodec\", \"libxvid\")\n                .AddArg(\"qscale:v\", qscale);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/Codecs/YouTubeLiveVideoCodec.cs",
    "content": "﻿namespace Captura.FFmpeg\n{\n    class YouTubeLiveVideoCodec : StreamingVideoCodec\n    {\n        public YouTubeLiveVideoCodec() : base(\"YouTube Live\", \"Stream to YouTube Live (Not Tested)\") { }\n\n        protected override string GetLink(FFmpegSettings Settings)\n        {\n            return $\"rtmp://a.rtmp.youtube.com/live2/{Settings.YouTubeLiveKey}\";\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/FFmpegGifConverter.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    // ReSharper disable once InconsistentNaming\n    class FFmpegGifConverter : IVideoConverter\n    {\n        public string Name => \"Gif (FFmpeg)\";\n\n        public string Extension => \".gif\";\n\n        public async Task StartAsync(VideoConverterArgs Args, IProgress<int> Progress)\n        {\n            if (!FFmpegService.FFmpegExists)\n            {\n                throw new FFmpegNotFoundException();\n            }\n\n            var argsBuilder = new FFmpegArgsBuilder();\n\n            argsBuilder.AddInputFile(Args.InputFile);\n\n            const string filter = \"\\\"[0:v] split [a][b];[a] palettegen [p];[b][p] paletteuse\\\"\";\n\n            argsBuilder.AddOutputFile(Args.FileName)\n                .AddArg(\"filter_complex\", filter)\n                .SetFrameRate(Args.FrameRate);\n\n            var process = FFmpegService.StartFFmpeg(argsBuilder.GetArgs(), Args.FileName, out var log);\n            log.ProgressChanged += Progress.Report;\n\n            await Task.Run(() => process.WaitForExit());\n\n            if (process.ExitCode != 0)\n                throw new FFmpegException(process.ExitCode);\n\n            Progress.Report(100);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.FFmpeg/Video/FFmpegReplayWriter.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Threading.Tasks;\nusing Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    public class FFmpegReplayWriter : IVideoFileWriter\n    {\n        readonly VideoWriterArgs _videoWriterArgs;\n        readonly int _duration;\n        readonly long _frameCount;\n        long _currentFrame = -1;\n\n        const int NoOfFiles = 2;\n        int _currentFile = -1;\n\n        readonly Func<VideoWriterArgs, IVideoFileWriter> _writerGenerator;\n\n        IVideoFileWriter _currentWriter;\n\n        string GetFileName(int Index)\n        {\n            return $\"{_videoWriterArgs.FileName}.{Index}.mp4\";\n        }\n\n        public FFmpegReplayWriter(VideoWriterArgs VideoWriterArgs,\n            int Duration,\n            Func<VideoWriterArgs, IVideoFileWriter> WriterGenerator)\n        {\n            _videoWriterArgs = VideoWriterArgs;\n            _duration = Duration;\n            _writerGenerator = WriterGenerator;\n            _frameCount = _videoWriterArgs.FrameRate * Duration;\n        }\n\n        public void Dispose()\n        {\n            _prevWriterDisposeTask?.Wait();\n            _currentWriter?.Dispose();\n\n            var currentFile = GetFileName(_currentFile);\n            var prevFile = GetFileName((_currentFile - 1 + NoOfFiles) % NoOfFiles);\n\n            var currentDuration = _currentFrame * 1000 / _videoWriterArgs.FrameRate;\n            var prevDuration = _duration * 1000 - currentDuration;\n\n            // Prev file only\n            if (currentDuration == 0 && File.Exists(prevFile))\n            {\n                File.Move(prevFile, _videoWriterArgs.FileName);\n            }\n            else if (prevDuration == 0 || !File.Exists(prevFile)) // Current file only\n            {\n                File.Move(currentFile, _videoWriterArgs.FileName);\n            }\n            else // Concat\n            {\n                var argsBuilder = new FFmpegArgsBuilder();\n\n                argsBuilder.AddInputFile(prevFile)\n                    .AddArg(\"ss\", $\"{TimeSpan.FromMilliseconds(currentDuration):g}\");\n\n                argsBuilder.AddInputFile(currentFile);\n\n                var hasAudio = _videoWriterArgs.AudioProvider != null;\n\n                const string filter = \"[0:v] [1:v] concat=n=2:v=1:a=0 [v]\";\n                const string filterWithAudio = \"[0:v] [0:a] [1:v] [1:a] concat=n=2:v=1:a=1 [v] [a]\";\n\n                var output = argsBuilder.AddOutputFile(_videoWriterArgs.FileName)\n                    .AddArg($\"-filter_complex \\\"{(hasAudio ? filterWithAudio : filter)}\\\"\")\n                    .AddArg(\"-map \\\"[v]\\\"\");\n\n                if (hasAudio)\n                    output.AddArg(\"-map \\\"[a]\\\"\");\n\n                var args = argsBuilder.GetArgs();\n\n                var process = FFmpegService.StartFFmpeg(args, _videoWriterArgs.FileName, out _);\n\n                process.WaitForExit();\n            }\n\n            for (var i = 0; i < NoOfFiles; i++)\n            {\n                var filename = GetFileName(i);\n\n                if (File.Exists(filename))\n                {\n                    File.Delete(filename);\n                }\n            }\n        }\n\n        Task _prevWriterDisposeTask;\n\n        IVideoFileWriter GetWriter()\n        {\n            ++_currentFrame;\n            _currentFrame %= _frameCount;\n\n            if (_currentFrame == 0)\n            {\n                if (_currentWriter != null)\n                {\n                    _prevWriterDisposeTask?.Wait();\n\n                    var prevWriter = _currentWriter;\n                    _prevWriterDisposeTask = Task.Run(() => prevWriter.Dispose());\n\n                    _currentWriter = null;\n                }\n\n                ++_currentFile;\n                _currentFile %= NoOfFiles;\n            }\n\n            return _currentWriter ??= _writerGenerator(new VideoWriterArgs\n            {\n                FileName = GetFileName(_currentFile),\n                VideoQuality = _videoWriterArgs.VideoQuality,\n                FrameRate = _videoWriterArgs.FrameRate,\n                ImageProvider = _videoWriterArgs.ImageProvider,\n                AudioProvider = _videoWriterArgs.AudioProvider,\n                AudioQuality = _videoWriterArgs.AudioQuality\n            });\n        }\n\n        readonly object _syncLock = new object();\n\n        public void WriteFrame(IBitmapFrame Image)\n        {\n            IVideoFileWriter writer;\n\n            lock (_syncLock)\n            {\n                writer = GetWriter();\n            }\n\n            writer.WriteFrame(Image);\n        }\n\n        public bool SupportsAudio => true;\n\n        public void WriteAudio(byte[] Buffer, int Offset, int Length)\n        {\n            IVideoFileWriter writer;\n\n            lock (_syncLock)\n            {\n                writer = _currentWriter;\n            }\n\n            writer?.WriteAudio(Buffer, Offset, Length);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/FFmpegVideoConverter.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    // ReSharper disable once InconsistentNaming\n    class FFmpegVideoConverter : IVideoConverter\n    {\n        readonly FFmpegVideoCodec _videoCodec;\n\n        public FFmpegVideoConverter(FFmpegVideoCodec VideoCodec)\n        {\n            _videoCodec = VideoCodec;\n        }\n\n        public string Name => $\"{_videoCodec.Name} (FFmpeg)\";\n\n        public string Extension => _videoCodec.Extension;\n\n        public async Task StartAsync(VideoConverterArgs Args, IProgress<int> Progress)\n        {\n            if (!FFmpegService.FFmpegExists)\n            {\n                throw new FFmpegNotFoundException();\n            }\n\n            var argsBuilder = new FFmpegArgsBuilder();\n\n            argsBuilder.AddInputFile(Args.InputFile);\n\n            var output = argsBuilder.AddOutputFile(Args.FileName)\n                .SetFrameRate(Args.FrameRate);\n\n            _videoCodec.Apply(ServiceProvider.Get<FFmpegSettings>(), Args, output);\n\n            //if (Args.AudioProvider != null)\n            {\n                _videoCodec.AudioArgsProvider(Args.AudioQuality, output);\n            }\n\n            var process = FFmpegService.StartFFmpeg(argsBuilder.GetArgs(), Args.FileName, out var log);\n\n            log.ProgressChanged += Progress.Report;\n\n            await Task.Run(() => process.WaitForExit());\n\n            if (process.ExitCode != 0)\n                throw new FFmpegException(process.ExitCode);\n\n            Progress.Report(100);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.FFmpeg/Video/FFmpegVideoWriter.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.IO.Pipes;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    /// <summary>\n    /// Encode Video using FFmpeg.exe\n    /// </summary>\n    class FFmpegWriter : IVideoFileWriter\n    {\n        readonly NamedPipeServerStream _audioPipe;\n\n        readonly Process _ffmpegProcess;\n        readonly NamedPipeServerStream _ffmpegIn;\n        byte[] _videoBuffer;\n\n        // This semaphore helps prevent FFmpeg audio/video pipes getting deadlocked.\n        readonly SemaphoreSlim _spVideo = new SemaphoreSlim(5);\n\n        // Timeout used with Semaphores, if elapsed would mean FFmpeg might be deadlocked.\n        readonly TimeSpan _spTimeout = TimeSpan.FromMilliseconds(50);\n\n        static string GetPipeName() => $\"captura-{Guid.NewGuid()}\";\n\n        /// <summary>\n        /// Creates a new instance of <see cref=\"FFmpegWriter\"/>.\n        /// </summary>\n        public FFmpegWriter(FFmpegVideoWriterArgs Args)\n        {\n            if (!FFmpegService.FFmpegExists)\n            {\n                throw new FFmpegNotFoundException();\n            }\n\n            var nv12 = Args.ImageProvider.DummyFrame is INV12Frame;\n\n            var settings = ServiceProvider.Get<FFmpegSettings>();\n\n            var w = Args.ImageProvider.Width;\n            var h = Args.ImageProvider.Height;\n\n            _videoBuffer = new byte[(int)(w * h * (nv12 ? 1.5 : 4))];\n\n            Console.WriteLine($\"Video Buffer Allocated: {_videoBuffer.Length}\");\n\n            var videoPipeName = GetPipeName();\n\n            var argsBuilder = new FFmpegArgsBuilder();\n\n            argsBuilder.AddInputPipe(videoPipeName)\n                .AddArg(\"thread_queue_size\", 512)\n                .AddArg(\"framerate\", Args.FrameRate)\n                .SetFormat(\"rawvideo\")\n                .AddArg(\"pix_fmt\", nv12 ? \"nv12\" : \"rgb32\")\n                .SetVideoSize(w, h);\n\n            var output = argsBuilder.AddOutputFile(Args.FileName)\n                .SetFrameRate(Args.FrameRate);\n\n            Args.VideoCodec.Apply(settings, Args, output);\n            \n            if (settings.Resize)\n            {\n                var width = settings.ResizeWidth;\n                var height = settings.ResizeHeight;\n\n                if (width % 2 == 1)\n                    ++width;\n\n                if (height % 2 == 1)\n                    ++height;\n\n                output.AddArg(\"vf\", $\"scale={width}:{height}\");\n            }\n\n            if (Args.AudioProvider != null)\n            {\n                var audioPipeName = GetPipeName();\n\n                argsBuilder.AddInputPipe(audioPipeName)\n                    .AddArg(\"thread_queue_size\", 512)\n                    .SetFormat(\"s16le\")\n                    .SetAudioCodec(\"pcm_s16le\")\n                    .SetAudioFrequency(Args.Frequency)\n                    .SetAudioChannels(Args.Channels);\n\n                Args.VideoCodec.AudioArgsProvider(Args.AudioQuality, output);\n\n                var wf = Args.AudioProvider.WaveFormat;\n\n                _audioBytesPerFrame = (int)((1.0 / Args.FrameRate)\n                                            * wf.SampleRate\n                                            * wf.Channels\n                                            * (wf.BitsPerSample / 8.0));\n\n                // UpdatePeriod * Frequency * (Bytes per Second) * Channels * 2\n                var audioBufferSize = (int)((1000.0 / Args.FrameRate) * 44.1 * 2 * 2 * 2);\n\n                _audioPipe = new NamedPipeServerStream(audioPipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 0, audioBufferSize);\n            }\n\n            _ffmpegIn = new NamedPipeServerStream(videoPipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 0, _videoBuffer.Length);\n\n            _ffmpegProcess = FFmpegService.StartFFmpeg(argsBuilder.GetArgs(), Args.FileName, out _);\n        }\n\n        /// <summary>\n        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\n        /// </summary>\n        public void Dispose()\n        {\n            _lastFrameTask?.Wait();\n            _lastAudio?.Wait();\n\n            _ffmpegIn.Dispose();\n\n            _audioPipe?.Dispose();\n\n            _ffmpegProcess.WaitForExit();\n\n            _videoBuffer = null;\n        }\n\n        /// <summary>\n        /// Gets whether audio is supported.\n        /// </summary>\n        public bool SupportsAudio { get; } = true;\n\n        bool _firstAudio = true;\n\n        Task _lastAudio;\n\n        /// <summary>\n        /// Write audio block to Audio Stream.\n        /// </summary>\n        /// <param name=\"Buffer\">Buffer containing audio data.</param>\n        /// <param name=\"Length\">Length of audio data in bytes.</param>\n        public void WriteAudio(byte[] Buffer, int Offset, int Length)\n        {\n            // Might happen when writing Gif\n            if (_audioPipe == null)\n                return;\n\n            if (_ffmpegProcess.HasExited)\n            {\n                throw new FFmpegException( _ffmpegProcess.ExitCode);\n            }\n\n            if (_firstAudio)\n            {\n                if (!_audioPipe.WaitForConnection(5000))\n                {\n                    throw new Exception(\"Cannot connect Audio pipe to FFmpeg\");\n                }\n\n                _firstAudio = false;\n            }\n\n            // We don't need semaphores for audio since audio frames arrive less often.\n            _lastAudio?.Wait();\n\n            // Drop audio bytes to sync with video once we've reached stability from frame side.\n            if (_initialStability)\n            {\n                var audioBytesToDrop = _skippedFrames * _audioBytesPerFrame - _audioBytesDropped;\n\n                // Drop whole buffer\n                if (audioBytesToDrop >= Length)\n                {\n                    _audioBytesDropped += Length;\n                    return;\n                }\n\n                // Drop part of buffer\n                if (audioBytesToDrop > 0)\n                {\n                    Offset += audioBytesToDrop;\n                    Length -= audioBytesToDrop;\n                    _audioBytesDropped += audioBytesToDrop;\n                }\n            }\n\n            _lastAudio = _audioPipe.WriteAsync(Buffer, Offset, Length);\n        }\n\n        bool _firstFrame = true;\n\n        bool _initialStability;\n        int _frameStreak;\n        const int FrameStreakThreshold = 50;\n        int _skippedFrames;\n        readonly int _audioBytesPerFrame;\n        int _audioBytesDropped;\n\n        Task _lastFrameTask;\n\n        /// <summary>\n        /// Writes an Image frame.\n        /// </summary>\n        public void WriteFrame(IBitmapFrame Frame)\n        {\n            if (_ffmpegProcess.HasExited)\n            {\n                Frame.Dispose();\n                throw new FFmpegException(_ffmpegProcess.ExitCode);\n            }\n            \n            if (_firstFrame)\n            {\n                if (!_ffmpegIn.WaitForConnection(5000))\n                {\n                    throw new Exception(\"Cannot connect Video pipe to FFmpeg\");\n                }\n\n                _firstFrame = false;\n            }\n\n            if (_lastFrameTask == null)\n            {\n                _lastFrameTask = Task.CompletedTask;\n            }\n\n            if (!(Frame is RepeatFrame))\n            {\n                using (Frame)\n                {\n                    if (Frame.Unwrap() is INV12Frame nv12Frame)\n                    {\n                        nv12Frame.CopyNV12To(_videoBuffer);\n                    }\n                    else Frame.CopyTo(_videoBuffer);\n                }\n            }\n\n            // Drop frames if semaphore cannot be acquired soon enough.\n            // Frames are dropped mostly in the beginning of recording till atleast one audio frame is received.\n            if (!_spVideo.Wait(_spTimeout))\n            {\n                ++_skippedFrames;\n                _frameStreak = 0;\n                return;\n            }\n            \n            // Most of the drops happen in beginning of video, once that stops, sync can be done.\n            if (!_initialStability)\n            {\n                ++_frameStreak;\n                if (_frameStreak > FrameStreakThreshold)\n                {\n                    _initialStability = true;\n                }\n            }\n\n            try\n            {\n                // Check if last write failed.\n                if (_lastFrameTask != null && _lastFrameTask.IsFaulted)\n                {\n                    _lastFrameTask.Wait();\n                }\n\n                _lastFrameTask = _lastFrameTask.ContinueWith(async M =>\n                {\n                    try\n                    {\n                        await _ffmpegIn.WriteAsync(_videoBuffer, 0, _videoBuffer.Length);\n                    }\n                    finally\n                    {\n                        _spVideo.Release();\n                    }\n                });\n            }\n            catch (Exception e) when (_ffmpegProcess.HasExited)\n            {\n                throw new FFmpegException(_ffmpegProcess.ExitCode, e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.FFmpeg/Video/FFmpegVideoWriterArgs.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    class FFmpegVideoWriterArgs : VideoWriterArgs\n    {\n        public static FFmpegVideoWriterArgs FromVideoWriterArgs(VideoWriterArgs Args, FFmpegVideoCodec VideoCodec)\n        {\n            return new FFmpegVideoWriterArgs\n            {\n                FileName = Args.FileName,\n                ImageProvider = Args.ImageProvider,\n                FrameRate = Args.FrameRate,\n                VideoQuality = Args.VideoQuality,\n                VideoCodec = VideoCodec,\n                AudioQuality = Args.AudioQuality,\n                AudioProvider = Args.AudioProvider\n            };\n        }\n\n        public FFmpegVideoCodec VideoCodec { get; set; }\n        public int Frequency { get; set; } = 44100;\n        public int Channels { get; set; } = 2;\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/FFmpegWriterProvider.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FFmpegWriterProvider : IVideoWriterProvider\n    {\n        public string Name => \"FFmpeg\";\n\n        readonly FFmpegSettings _settings;\n\n        public FFmpegWriterProvider(FFmpegSettings Settings)\n        {\n            _settings = Settings;\n        }\n\n        public IEnumerator<IVideoWriterItem> GetEnumerator()\n        {\n            yield return new X264VideoCodec();\n            yield return new XvidVideoCodec();\n\n            // Hardware\n            yield return new QsvHevcVideoCodec();\n            yield return NvencVideoCodec.CreateH264();\n            yield return NvencVideoCodec.CreateHevc();\n\n            // Custom\n            foreach (var item in _settings.CustomCodecs)\n            {\n                yield return new CustomFFmpegVideoCodec(item);\n            }\n        }\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        public override string ToString() => Name;\n\n        public IVideoWriterItem ParseCli(string Cli)\n        {\n            var ffmpegExists = FFmpegService.FFmpegExists;\n\n            if (ffmpegExists && Regex.IsMatch(Cli, @\"^ffmpeg:\\d+$\"))\n            {\n                var index = int.Parse(Cli.Substring(7));\n\n                var writers = this.ToArray();\n\n                if (index < writers.Length)\n                {\n                    return writers[index];\n                }\n            }\n\n            return null;\n        }\n\n        public string Description => @\"Use FFmpeg for encoding.\nRequires ffmpeg.exe, if not found option for downloading or specifying path is shown.\";\n    }\n}"
  },
  {
    "path": "src/Captura.FFmpeg/Video/StreamingWriterProvider.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing Captura.Video;\n\nnamespace Captura.FFmpeg\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class StreamingWriterProvider : IVideoWriterProvider\n    {\n        public string Name => \"Stream\";\n\n        public IEnumerator<IVideoWriterItem> GetEnumerator()\n        {\n            yield return new TwitchVideoCodec();\n            yield return new YouTubeLiveVideoCodec();\n            yield return new CustomStreamingVideoCodec();\n        }\n\n        public static IVideoWriterItem GetCustomStreamingCodec() => new CustomStreamingVideoCodec();\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        public override string ToString() => Name;\n\n        public IVideoWriterItem ParseCli(string Cli)\n        {\n            var ffmpegExists = FFmpegService.FFmpegExists;\n\n            if (ffmpegExists && Regex.IsMatch(Cli, @\"^ffmpeg:\\d+$\"))\n            {\n                var index = int.Parse(Cli.Substring(7));\n\n                var writers = this.ToArray();\n\n                if (index < writers.Length)\n                {\n                    return writers[index];\n                }\n            }\n\n            return null;\n        }\n\n        public string Description => @\"Stream to streaming sites using FFmpeg (Alpha).\nAPI keys can be set on FFmpeg settings page.\";\n    }\n}"
  },
  {
    "path": "src/Captura.Fakes/Captura.Fakes.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n    <ProjectReference Include=\"..\\Captura.FFmpeg\\Captura.FFmpeg.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Loc\\Captura.Loc.csproj\" />\n    <ProjectReference Include=\"..\\Screna\\Screna.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Captura.Fakes/FakeAudioPlayer.cs",
    "content": "﻿using Captura.Audio;\n\nnamespace Captura.Fakes\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FakeAudioPlayer : IAudioPlayer\n    {\n        public void Play(SoundKind SoundKind) { }\n    }\n}"
  },
  {
    "path": "src/Captura.Fakes/FakeFFmpegLogRepository.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing Captura.FFmpeg;\n\nnamespace Captura.Fakes\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FakeFFmpegLogRepository : IFFmpegLogRepository\n    {\n        public IEnumerator<IFFmpegLogEntry> GetEnumerator()\n        {\n            yield break;\n        }\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        public IFFmpegLogEntry CreateNew(string Name, string Args)\n        {\n            return new FFmpegLogItem(Name, Args);\n        }\n\n        public void Remove(IFFmpegLogEntry Entry)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Fakes/FakeFFmpegViewsProvider.cs",
    "content": "﻿using System;\nusing Captura.FFmpeg;\n\nnamespace Captura.Fakes\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class FakeFFmpegViewsProvider : IFFmpegViewsProvider\n    {\n        public void ShowLogs()\n        {\n        }\n\n        public void ShowUnavailable()\n        {\n            Console.Error.WriteLine(\"FFmpeg is not available.\\nYou can install ffmpeg by calling: captura ffmpeg --install [path]\");\n        }\n\n        public void ShowDownloader()\n        {\n        }\n\n        public void PickFolder()\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Fakes/FakeMessageProvider.cs",
    "content": "﻿using System;\nusing Captura.Models;\n\nnamespace Captura.Fakes\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class FakeMessageProvider : IMessageProvider\n    {\n        public void ShowError(string Message, string Header = null)\n        {\n            if (Header != null)\n                Console.WriteLine(Header);\n\n            Console.Error.WriteLine(Message);\n        }\n\n        public void ShowException(Exception Exception, string Message, bool Blocking = false)\n        {\n            ShowError(Exception.ToString());\n        }\n\n        public bool ShowYesNo(string Message, string Title)\n        {\n            Console.Write($\"{Message} (Y/N): \");\n\n            var reply = Console.ReadLine();\n\n            return reply != null && reply.ToLower() == \"y\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Fakes/FakePreviewWindow.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.Fakes\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FakePreviewWindow : IPreviewWindow\n    {\n        public void Dispose() { }\n\n        public void Display(IBitmapFrame Frame)\n        {\n            Frame.Dispose();\n        }\n\n        public void Show() { }\n\n        public bool IsVisible => false;\n    }\n}"
  },
  {
    "path": "src/Captura.Fakes/FakeRegionProvider.cs",
    "content": "﻿using System.Drawing;\nusing System;\nusing Captura.Video;\n\nnamespace Captura.Fakes\n{\n    public class FakeRegionProvider : IRegionProvider\n    {\n        FakeRegionProvider() { }\n\n        public static FakeRegionProvider Instance { get; } = new FakeRegionProvider();\n\n        public bool SelectorVisible\n        {\n            get => false;\n            set { }\n        }\n        \n        public Rectangle SelectedRegion { get; set; }\n\n        public IVideoItem VideoSource => new RegionItem(this, ServiceProvider.Get<IPlatformServices>());\n\n#pragma warning disable CS0067\n        public event Action SelectorHidden;\n#pragma warning restore CS0067\n\n        public IntPtr Handle => IntPtr.Zero;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Fakes/FakeSystemTray.cs",
    "content": "﻿using System;\nusing Captura.Loc;\nusing Captura.Models;\n\nnamespace Captura.Fakes\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class FakeSystemTray : ISystemTray\n    {\n        readonly ILocalizationProvider _loc;\n\n        public FakeSystemTray(ILocalizationProvider Loc)\n        {\n            _loc = Loc;\n        }\n\n        public void HideNotification() { }\n\n        public void ShowScreenShotNotification(string FilePath)\n        {\n            // ReSharper disable once LocalizableElement\n            Console.WriteLine($\"{_loc.ScreenShotSaved}: {FilePath}\");\n        }\n\n        public void ShowNotification(INotification Notification) { }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Fakes/FakeVideoSourcePicker.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Video;\n\nnamespace Captura.Fakes\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FakeVideoSourcePicker : IVideoSourcePicker\n    {\n        FakeVideoSourcePicker() { }\n\n        public static FakeVideoSourcePicker Instance { get; } = new FakeVideoSourcePicker();\n\n        public IWindow SelectedWindow { get; set; }\n\n        public IWindow PickWindow(Predicate<IWindow> Filter = null) => SelectedWindow;\n\n        public IScreen SelectedScreen { get; set; }\n\n        public IScreen PickScreen() => SelectedScreen;\n\n        public Rectangle? PickRegion() => null;\n    }\n}"
  },
  {
    "path": "src/Captura.Fakes/FakeWindowProvider.cs",
    "content": "﻿using Captura.Models;\n\nnamespace Captura.Fakes\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class FakeWindowProvider : IMainWindow\n    {\n        public bool IsVisible\n        {\n            get => true;\n            set { }\n        }\n\n        public bool IsMinimized\n        {\n            get => false;\n            set { }\n        }\n\n        public void EditImage(string FileName) { }\n\n        public void CropImage(string FileName) { }\n\n        public void TrimMedia(string FileName) { }\n\n        public void UploadToYouTube(string FileName) { }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Fakes/FakesModule.cs",
    "content": "﻿using Captura.Audio;\nusing Captura.FFmpeg;\nusing Captura.Models;\nusing Captura.Video;\n\nnamespace Captura.Fakes\n{\n    public class FakesModule : IModule\n    {\n        public void OnLoad(IBinder Binder)\n        {\n            Binder.Bind<IMessageProvider, FakeMessageProvider>();\n            Binder.Bind<IRegionProvider>(() => FakeRegionProvider.Instance);\n            Binder.Bind<ISystemTray, FakeSystemTray>();\n            Binder.Bind<IMainWindow, FakeWindowProvider>();\n            Binder.Bind<IPreviewWindow, FakePreviewWindow>();\n            Binder.Bind<IVideoSourcePicker>(() => FakeVideoSourcePicker.Instance);\n            Binder.Bind<IAudioPlayer, FakeAudioPlayer>();\n            Binder.Bind<IFFmpegViewsProvider, FakeFFmpegViewsProvider>();\n            Binder.Bind<IFFmpegLogRepository, FakeFFmpegLogRepository>();\n        }\n\n        public void Dispose() { }\n    }\n}"
  },
  {
    "path": "src/Captura.Hotkeys/Captura.Hotkeys.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net472</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"System.Windows.Forms\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Loc\\Captura.Loc.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"11.0.2\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Captura.Hotkeys/HotKey.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Windows.Forms;\nusing Captura.Native;\n\nnamespace Captura.Hotkeys\n{\n    public class Hotkey : NotifyPropertyChanged\n    {\n        Service _service;\n\n        public Service Service\n        {\n            get => _service;\n            set => Set(ref _service, value);\n        }\n\n        public Hotkey(HotkeyModel Model)\n        {\n            Service = HotKeyManager.AllServices.FirstOrDefault(M => M.ServiceName == Model.ServiceName);\n            Key = Model.Key;\n            Modifiers = Model.Modifiers;\n\n            IsActive = Model.IsActive;\n        }\n\n        bool _active;\n\n        public bool IsActive\n        {\n            get => _active;\n            set\n            {\n                _active = value;\n\n                if (value && !IsRegistered)\n                {\n                    Register();\n                }\n                else if (!value && IsRegistered)\n                {\n                    Unregister();\n                }\n\n                OnPropertyChanged();\n            }\n        }\n\n        public bool IsRegistered { get; private set; }\n\n        public ushort Id { get; private set; }\n\n        public void Register()\n        {\n            if (IsRegistered || Key == Keys.None)\n                return;\n\n            // Generate Unique ID\n            var uid = Guid.NewGuid().ToString(\"N\");\n            Id = Kernel32.GlobalAddAtom(uid);\n            \n            if (User32.RegisterHotKey(IntPtr.Zero, Id, (int) Modifiers, (uint) Key))\n                IsRegistered = true;\n            else\n            {\n                Kernel32.GlobalDeleteAtom(Id);\n                Id = 0;\n            }\n        }\n        \n        public Keys Key { get; private set; }\n\n        public Modifiers Modifiers { get; private set; }\n\n        public void Change(Keys NewKey, Modifiers NewModifiers)\n        {\n            Unregister();\n\n            Key = NewKey;\n            Modifiers = NewModifiers;\n\n            Register();\n        }\n\n        public void Unregister()\n        {\n            if (!IsRegistered)\n                return;\n\n            if (User32.UnregisterHotKey(IntPtr.Zero, Id))\n            {\n                IsRegistered = false;\n\n                Kernel32.GlobalDeleteAtom(Id);\n                Id = 0;\n            }\n        }\n\n        public override string ToString()\n        {\n            var text = \"\";\n\n            if (Modifiers.HasFlag(Modifiers.Ctrl))\n                text += \"Ctrl + \";\n\n            if (Modifiers.HasFlag(Modifiers.Alt))\n                text += \"Alt + \";\n\n            if (Modifiers.HasFlag(Modifiers.Shift))\n                text += \"Shift + \";\n\n            // Handle Number keys\n            if (Key >= Keys.D0 && Key <= Keys.D9)\n            {\n                text += Key - Keys.D0;\n            }\n            else if (Key >= Keys.NumPad0 && Key <= Keys.NumPad9)\n            {\n                text += Key - Keys.NumPad0;\n            }\n            else text += Key;\n\n            return text;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Hotkeys/HotKeyManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.IO;\nusing System.Linq;\nusing System.Windows.Forms;\nusing Newtonsoft.Json;\n\nnamespace Captura.Hotkeys\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class HotKeyManager : IDisposable\n    {\n        readonly ObservableCollection<Hotkey> _hotkeys = new ObservableCollection<Hotkey>();\n\n        public ReadOnlyObservableCollection<Hotkey> Hotkeys { get; }\n\n        static string GetFilePath() => Path.Combine(ServiceProvider.SettingsDir, \"Hotkeys.json\");\n\n        public HotKeyManager(IHotkeyListener HotkeyListener,\n            IEnumerable<IHotkeyActor> HotkeyActors)\n        {\n            Hotkeys = new ReadOnlyObservableCollection<Hotkey>(_hotkeys);\n\n            HotkeyListener.HotkeyReceived += ProcessHotkey;\n            HotkeyPressed += M =>\n            {\n                foreach (var actor in HotkeyActors)\n                {\n                    actor.Act(M);\n                }\n            };\n        }\n\n        public void Remove(Hotkey Hotkey)\n        {\n            Hotkey.Unregister();\n\n            _hotkeys.Remove(Hotkey);\n        }\n\n        public void Add()\n        {\n            var hotkey = new Hotkey(new HotkeyModel(ServiceName.None, Keys.None, Modifiers.None, false));\n\n            _hotkeys.Add(hotkey);\n        }\n\n        public static IEnumerable<Service> AllServices { get; } = Enum\n            .GetValues(typeof(ServiceName))\n            .Cast<ServiceName>()\n            .Select(M => new Service(M))\n            .ToArray(); // Prevent multiple enumerations\n\n        public void RegisterAll()\n        {\n            IEnumerable<HotkeyModel> models;\n\n            try\n            {\n                var json = File.ReadAllText(GetFilePath());\n\n                models = JsonConvert.DeserializeObject<IEnumerable<HotkeyModel>>(json);\n            }\n            catch\n            {\n                models = Defaults();\n            }\n\n            Populate(models);\n        }\n\n        public void Reset()\n        {\n            Dispose();\n\n            _hotkeys.Clear();\n\n            Populate(Defaults());\n        }\n\n        void Populate(IEnumerable<HotkeyModel> Models)\n        {\n            foreach (var model in Models)\n            {\n                var hotkey = new Hotkey(model);\n\n                _hotkeys.Add(hotkey);\n            }\n        }\n\n        static IEnumerable<HotkeyModel> Defaults()\n        {\n            return new[]\n            {\n                new HotkeyModel(ServiceName.Recording, Keys.F9, Modifiers.Alt, true),\n                new HotkeyModel(ServiceName.Pause, Keys.F9, Modifiers.Shift, true),\n                new HotkeyModel(ServiceName.ScreenShot, Keys.PrintScreen, 0, true),\n                new HotkeyModel(ServiceName.ActiveScreenShot, Keys.PrintScreen, Modifiers.Alt, true),\n                new HotkeyModel(ServiceName.DesktopScreenShot, Keys.PrintScreen, Modifiers.Shift, true)\n            };\n        }\n        \n        void ProcessHotkey(int Id)\n        {\n            var hotkey = Hotkeys.SingleOrDefault(H => H.Id == Id);\n\n            if (hotkey != null)\n                HotkeyPressed?.Invoke(hotkey.Service.ServiceName);\n        }\n\n        public void FakeHotkey(ServiceName Service)\n        {\n            HotkeyPressed?.Invoke(Service);\n        }\n\n        event Action<ServiceName> HotkeyPressed;\n        \n        public void Dispose()\n        {\n            var models = Hotkeys.Select(M =>\n            {\n                M.Unregister();\n\n                return new HotkeyModel(M.Service.ServiceName, M.Key, M.Modifiers, M.IsActive);\n            });\n\n            try\n            {\n                var json = JsonConvert.SerializeObject(models);\n\n                File.WriteAllText(GetFilePath(), json);\n            }\n            catch\n            {\n                // Ignore Errors\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Hotkeys/HotkeyModel.cs",
    "content": "﻿using System.Windows.Forms;\n// ReSharper disable MemberCanBePrivate.Global\n// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global\n\nnamespace Captura.Hotkeys\n{\n    public class HotkeyModel\n    {\n        public HotkeyModel(ServiceName ServiceName, Keys Key, Modifiers Modifiers, bool IsActive)\n        {\n            this.ServiceName = ServiceName;\n            this.Key = Key;\n            this.Modifiers = Modifiers;\n            this.IsActive = IsActive;\n        }\n\n        // Default constructor required by Settings\n        // ReSharper disable once UnusedMember.Global\n        public HotkeyModel() { }\n\n        public bool IsActive { get; set; }\n\n        public ServiceName ServiceName { get; set; }\n\n        public Keys Key { get; set; }\n\n        public Modifiers Modifiers { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Hotkeys/IHotkeyActor.cs",
    "content": "﻿namespace Captura.Hotkeys\n{\n    public interface IHotkeyActor\n    {\n        void Act(ServiceName Service);\n    }\n}"
  },
  {
    "path": "src/Captura.Hotkeys/IHotkeyListener.cs",
    "content": "﻿using System;\n\nnamespace Captura.Hotkeys\n{\n    public interface IHotkeyListener\n    {\n        event Action<int> HotkeyReceived;\n    }\n}"
  },
  {
    "path": "src/Captura.Hotkeys/Kernel32.cs",
    "content": "﻿using System.Runtime.InteropServices;\n\nnamespace Captura.Native\n{\n    static class Kernel32\n    {\n        const string DllName = \"kernel32\";\n\n        [DllImport(DllName)]\n        public static extern ushort GlobalAddAtom(string Text);\n\n        [DllImport(DllName)]\n        public static extern ushort GlobalDeleteAtom(ushort Atom);\n    }\n}"
  },
  {
    "path": "src/Captura.Hotkeys/Service.cs",
    "content": "﻿using System.Text;\nusing Captura.Loc;\n\nnamespace Captura.Hotkeys\n{\n    public class Service : NotifyPropertyChanged\n    {\n        readonly ILocalizationProvider _loc;\n\n        public Service(ServiceName ServiceName)\n        {\n            this.ServiceName = ServiceName;\n\n            _loc = ServiceProvider.Get<ILocalizationProvider>();\n\n            _loc.LanguageChanged += L => RaisePropertyChanged(nameof(Description));\n        }\n\n        ServiceName _serviceName;\n\n        public ServiceName ServiceName\n        {\n            get => _serviceName;\n            set\n            {\n                _serviceName = value;\n\n                OnPropertyChanged();\n\n                RaisePropertyChanged(nameof(Description));\n            }\n        }\n\n        public string Description => GetDescription();\n\n        string GetDescription()\n        {\n            switch (ServiceName)\n            {\n                case ServiceName.None:\n                    return _loc.None;\n\n                case ServiceName.Recording:\n                    return _loc.StartStopRecording;\n\n                case ServiceName.Pause:\n                    return _loc.PauseResumeRecording;\n\n                case ServiceName.ScreenShot:\n                    return _loc.ScreenShot;\n\n                case ServiceName.ActiveScreenShot:\n                    return _loc.ScreenShotActiveWindow;\n\n                case ServiceName.DesktopScreenShot:\n                    return _loc.ScreenShotDesktop;\n\n                case ServiceName.ToggleMouseClicks:\n                    return _loc.ToggleMouseClicks;\n\n                case ServiceName.ToggleKeystrokes:\n                    return _loc.ToggleKeystrokes;\n\n                case ServiceName.ScreenShotRegion:\n                    return \"Screenshot (Region)\";\n\n                case ServiceName.ScreenShotScreen:\n                    return \"ScreenShot (Screen)\";\n\n                case ServiceName.ScreenShotWindow:\n                    return \"ScreenShot (Window)\";\n\n                default:\n                    return SpaceAtCapitals(ServiceName);\n            }\n        }\n\n        static string SpaceAtCapitals<T>(T Obj)\n        {\n            var s = Obj.ToString();\n\n            var sb = new StringBuilder();\n\n            for (var i = 0; i < s.Length; ++i)\n            {\n                if (i != 0 && char.IsUpper(s[i]))\n                    sb.Append(\" \");\n\n                sb.Append(s[i]);\n            }\n\n            return sb.ToString();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Hotkeys/ServiceName.cs",
    "content": "﻿namespace Captura.Hotkeys\n{\n    public enum ServiceName\n    {\n        None = -1,\n\n        /// <summary>\n        /// ScreenShot.\n        /// </summary>\n        ScreenShot,\n\n        /// <summary>\n        /// Start/Stop Recording.\n        /// </summary>\n        Recording,\n\n        /// <summary>\n        /// Pause/Resume Recording.\n        /// </summary>\n        Pause,\n\n        /// <summary>\n        /// ScreenShot of Desktop.\n        /// </summary>\n        DesktopScreenShot,\n\n        /// <summary>\n        /// ScreenShot of Active Window.\n        /// </summary>\n        ActiveScreenShot,\n\n        /// <summary>\n        /// Toggle Mouse clicks overlay.\n        /// </summary>\n        ToggleMouseClicks,\n\n        /// <summary>\n        /// Toggle Keystrokes overlay.\n        /// </summary>\n        ToggleKeystrokes,\n\n        /// <summary>\n        /// Screenshot Region (using Region Picker).\n        /// </summary>\n        ScreenShotRegion,\n\n        /// <summary>\n        /// ScreenShot using Screen Picker.\n        /// </summary>\n        ScreenShotScreen,\n\n        /// <summary>\n        /// ScreenShot using Window Picker.\n        /// </summary>\n        ScreenShotWindow,\n\n        ShowMainWindow,\n\n        ToggleRegionPicker\n    }\n}\n"
  },
  {
    "path": "src/Captura.Hotkeys/User32.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\n// ReSharper disable InconsistentNaming\nnamespace Captura.Native\n{\n    static class User32\n    {\n        const string DllName = \"user32.dll\";\n\n        [DllImport(DllName)]\n        public static extern bool UnregisterHotKey(IntPtr Hwnd, int Id);\n\n        [DllImport(DllName)]\n        public static extern bool RegisterHotKey(IntPtr Hwnd, int Id, int Modifiers, uint VirtualKey);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Imgur/Captura.Imgur.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"11.0.2\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Captura.Imgur/IImgurApiKeys.cs",
    "content": "﻿namespace Captura.Imgur\n{\n    public interface IImgurApiKeys\n    {\n        string ImgurClientId { get; }\n\n        string ImgurSecret { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Imgur/ImgurData.cs",
    "content": "﻿using Newtonsoft.Json;\n\nnamespace Captura.Imgur\n{\n    class ImgurData\n    {\n        [JsonProperty(\"id\")]\n        public string Id { get; set; }\n\n        [JsonProperty(\"title\")]\n        public string Title { get; set; }\n\n        [JsonProperty(\"description\")]\n        public string Description { get; set; }\n\n        [JsonProperty(\"datetime\")]\n        public int DateTime { get; set; }\n\n        [JsonProperty(\"type\")]\n        public string Type { get; set; }\n\n        [JsonProperty(\"animated\")]\n        public bool Animated { get; set; }\n\n        [JsonProperty(\"width\")]\n        public int Width { get; set; }\n\n        [JsonProperty(\"height\")]\n        public int Height { get; set; }\n\n        [JsonProperty(\"size\")]\n        public int Size { get; set; }\n\n        [JsonProperty(\"views\")]\n        public int Views { get; set; }\n\n        [JsonProperty(\"deletehash\")]\n        public string DeleteHash { get; set; }\n\n        [JsonProperty(\"name\")]\n        public string Name { get; set; }\n\n        [JsonProperty(\"link\")]\n        public string Link { get; set; }\n\n        [JsonProperty(\"favorite\")]\n        public bool Favorite { get; set; }\n    }\n}"
  },
  {
    "path": "src/Captura.Imgur/ImgurRefreshTokenResponse.cs",
    "content": "﻿using Newtonsoft.Json;\n\nnamespace Captura.Imgur\n{\n    class ImgurRefreshTokenResponse\n    {\n        [JsonProperty(\"access_token\")]\n        public string AccessToken { get; set; }\n\n        [JsonProperty(\"refresh_token\")]\n        public string RefreshToken { get; set; }\n\n        [JsonProperty(\"expires_in\")]\n        public int ExpiresIn { get; set; }\n\n        [JsonProperty(\"token_type\")]\n        public string TokenType { get; set; }\n\n        [JsonProperty(\"account_username\")]\n        public string Username { get; set; }\n    }\n}"
  },
  {
    "path": "src/Captura.Imgur/ImgurResponse.cs",
    "content": "﻿using Newtonsoft.Json;\n\nnamespace Captura.Imgur\n{\n    class ImgurResponse\n    {\n        [JsonProperty(\"success\")]\n        public bool Success { get; set; }\n\n        [JsonProperty(\"status\")]\n        public int Status { get; set; }\n    }\n}"
  },
  {
    "path": "src/Captura.Imgur/ImgurSettings.cs",
    "content": "﻿using System;\n\nnamespace Captura.Imgur\n{\n    public class ImgurSettings : PropertyStore\n    {\n        public bool Anonymous\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n\n        public string AccessToken\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public string RefreshToken\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public DateTime ExpiresAt\n        {\n            get => Get(DateTime.MinValue);\n            set => Set(value);\n        }\n\n        /// <summary>\n        /// Checks if the Token expires in the next 10 seconds.\n        /// </summary>\n        public bool IsExpired()\n        {\n            return DateTime.UtcNow + TimeSpan.FromSeconds(10) > ExpiresAt;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Imgur/ImgurUploadResponse.cs",
    "content": "﻿using Newtonsoft.Json;\n\nnamespace Captura.Imgur\n{\n    class ImgurUploadResponse : ImgurResponse\n    {\n        [JsonProperty(\"data\")]\n        public ImgurData Data { get; set; }\n    }\n}"
  },
  {
    "path": "src/Captura.Imgur/ImgurUploader.cs",
    "content": "﻿using System;\nusing System.Collections.Specialized;\nusing System.IO;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Captura.Models;\nusing Newtonsoft.Json;\n\nnamespace Captura.Imgur\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ImgurUploader : IImageUploader\n    {\n        readonly ImgurSettings _settings;\n        readonly ProxySettings _proxySettings;\n        readonly IImgurApiKeys _apiKeys;\n\n        public ImgurUploader(ImgurSettings Settings,\n            ProxySettings ProxySettings,\n            IImgurApiKeys ApiKeys)\n        {\n            _settings = Settings;\n            _proxySettings = ProxySettings;\n            _apiKeys = ApiKeys;\n        }\n\n        public async Task<UploadResult> Upload(IBitmapImage Image, ImageFormats Format, Action<int> Progress)\n        {\n            using var w = new WebClient { Proxy = _proxySettings.GetWebProxy() };\n            if (Progress != null)\n            {\n                w.UploadProgressChanged += (S, E) => Progress(E.ProgressPercentage);\n            }\n\n            w.Headers.Add(\"Authorization\", await GetAuthorizationHeader());\n\n            NameValueCollection values;\n\n            using (var ms = new MemoryStream())\n            {\n                Image.Save(ms, Format);\n\n                values = new NameValueCollection\n                {\n                    { \"image\", Convert.ToBase64String(ms.ToArray()) }\n                };\n            }\n\n            var uploadResponse = await UploadValuesAsync<ImgurUploadResponse>(w, \"https://api.imgur.com/3/upload.json\", values);\n\n            if (!uploadResponse.Success)\n            {\n                throw new Exception(\"Response indicates Failure\");\n            }\n\n            return new UploadResult\n            {\n                Url = uploadResponse.Data.Link,\n                DeleteLink = $\"https://api.imgur.com/3/image/{uploadResponse.Data.DeleteHash}\"\n            };\n        }\n\n        async Task<string> GetAuthorizationHeader()\n        {\n            if (_settings.Anonymous)\n            {\n                return $\"Client-ID {_apiKeys.ImgurClientId}\";\n            }\n\n            if (string.IsNullOrWhiteSpace(_settings.AccessToken))\n            {\n                throw new Exception(\"Not logged in to Imgur\");\n            }\n\n            if (_settings.IsExpired())\n            {\n                if (!await RefreshToken())\n                {\n                    throw new Exception(\"Failed to Refresh Imgur token\");\n                }\n            }\n\n            return $\"Bearer {_settings.AccessToken}\";\n        }\n\n        async Task<bool> RefreshToken()\n        {\n            var args = new NameValueCollection\n            {\n                { \"refresh_token\", _settings.RefreshToken },\n                { \"client_id\", _apiKeys.ImgurClientId },\n                { \"client_secret\", _apiKeys.ImgurSecret },\n                { \"grant_type\", \"refresh_token\" }\n            };\n\n            using var w = new WebClient { Proxy = _proxySettings.GetWebProxy() };\n            var token = await UploadValuesAsync<ImgurRefreshTokenResponse>(w, \"https://api.imgur.com/oauth2/token.json\", args);\n\n            if (string.IsNullOrEmpty(token?.AccessToken))\n                return false;\n\n            _settings.AccessToken = token.AccessToken;\n            _settings.RefreshToken = token.RefreshToken;\n            _settings.ExpiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(token.ExpiresIn);\n            return true;\n        }\n\n        static async Task<T> UploadValuesAsync<T>(WebClient WebClient, string Url, NameValueCollection Values)\n        {\n            // Task.Run done to prevent UI thread from freezing when upload fails.\n            var response = await Task.Run(async () => await WebClient.UploadValuesTaskAsync(Url, Values));\n\n            return JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(response));\n        }\n\n        public async Task DeleteUploadedFile(string DeleteHash)\n        {\n            // DeleteHash is now complete Url\n            var request = WebRequest.Create(DeleteHash);\n\n            request.Proxy = _proxySettings.GetWebProxy();\n            request.Headers.Add(\"Authorization\", await GetAuthorizationHeader());\n            request.Method = \"DELETE\";\n\n            var stream = (await request.GetResponseAsync()).GetResponseStream();\n\n            if (stream != null)\n            {\n                var reader = new StreamReader(stream);\n\n                var text = await reader.ReadToEndAsync();\n\n                var res = JsonConvert.DeserializeObject<ImgurResponse>(text);\n\n                if (res.Success)\n                    return;\n            }\n\n            throw new Exception();\n        }\n\n        public string UploadServiceName { get; } = \"Imgur\";\n    }\n}"
  },
  {
    "path": "src/Captura.Loc/Captura.Loc.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"11.0.2\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Captura.Loc/ILocalizationProvider.cs",
    "content": "﻿using System;\nusing System.ComponentModel;\nusing System.Globalization;\n\nnamespace Captura.Loc\n{\n    public interface ILocalizationProvider : INotifyPropertyChanged\n    {\n        string About { get; }\n        string AccentColor { get; }\n        string Add { get; }\n        string AlwaysOnTop { get; }\n        string Audio { get; }\n        string AudioFormat { get; }\n        string AudioSaved { get; }\n        string BackColor { get; }\n        string BorderColor { get; }\n        string BorderThickness { get; }\n        string Bottom { get; }\n        string CaptureDuration { get; }\n        string Center { get; }\n        string Changelog { get; }\n        string Clear { get; }\n        string ClearRecentList { get; }\n        string Clipboard { get; }\n        string Close { get; }\n        string Color { get; }\n        string ConfigCodecs { get; }\n        string Configure { get; }\n        string CopyOutPathClipboard { get; }\n        string CopyPath { get; }\n        string CopyToClipboard { get; }\n        string CornerRadius { get; }\n        string CrashLogs { get; }\n        string Crop { get; }\n        string CustomSize { get; }\n        string CustomUrl { get; }\n        string DarkTheme { get; }\n        string Delete { get; }\n        string DiscardChanges { get; }\n        string Disk { get; }\n        string Donate { get; }\n        string DownloadFFmpeg { get; }\n        string Edit { get; }\n        string Elapsed { get; }\n        string ErrorOccurred { get; }\n        string Exit { get; }\n        string FFmpegFolder { get; }\n        string FFmpegLog { get; }\n        string FileMenu { get; }\n        string FileMenuNew { get; }\n        string FileMenuOpen { get; }\n        string FileMenuSave { get; }\n        string FileNaming { get; }\n        string FontSize { get; }\n        string FrameRate { get; }\n        string FullScreen { get; }\n        string HideOnFullScreenShot { get; }\n        string Host { get; }\n        string Hotkeys { get; }\n        string ImageEditor { get; }\n        string ImgEmpty { get; }\n        string ImgFormat { get; }\n        string ImgSavedClipboard { get; }\n        string ImageUploadFailed { get; }\n        string ImageUploadSuccess { get; }\n        string ImageUploading { get; }\n        string IncludeClicks { get; }\n        string IncludeCursor { get; }\n        string IncludeKeys { get; }\n        string Keymap { get; }\n        string Keystrokes { get; }\n        string KeystrokesHistoryCount { get; }\n        string KeystrokesHistorySpacing { get; }\n        string KeystrokesSeparateFile { get; }\n        string Language { get; }\n        string Left { get; }\n        string LoopbackSource { get; }\n        string MaxRecent { get; }\n        string MaxTextLength { get; }\n        string MicSource { get; }\n        string Minimize { get; }\n        string MinToTrayOnCaptureStart { get; }\n        string MinTray { get; }\n        string MinTrayStartup { get; }\n        string MinTrayClose { get; }\n        string MouseClicks { get; }\n        string MouseMiddleClickColor { get; }\n        string MousePointer { get; }\n        string MouseRightClickColor { get; }\n        string NewWindow { get; }\n        string No { get; }\n        string None { get; }\n        string Notifications { get; }\n        string NotSaved { get; }\n        string NoWebcam { get; }\n        string Ok { get; }\n        string OnlyAudio { get; }\n        string Opacity { get; }\n        string OpenFromClipboard { get; }\n        string OpenOutFolder { get; }\n        string OutFolder { get; }\n        string Overlays { get; }\n        string Padding { get; }\n        string Password { get; }\n        string Paused { get; }\n        string PauseResume { get; }\n        string PauseResumeRecording { get; }\n        string Port { get; }\n        string PreStartCountdown { get; }\n        string Preview { get; }\n        string Proxy { get; }\n        string Quality { get; }\n        string Radius { get; }\n        string Recent { get; }\n        string RecordStop { get; }\n        string Redo { get; }\n        string Refresh { get; }\n        string Region { get; }\n        string RegionSelector { get; }\n        string RemoveFromList { get; }\n        string Reset { get; }\n        string Resize { get; }\n        string RestoreDefaults { get; }\n        string Right { get; }\n        string SaveToClipboard { get; }\n        string Screen { get; }\n        string ScreenShot { get; }\n        string ScreenShotActiveWindow { get; }\n        string ScreenShotDesktop { get; }\n        string ScreenShotSaved { get; }\n        string SelectFFmpegFolder { get; }\n        string SelectOutFolder { get; }\n        string SeparateAudioFiles { get; }\n        string ShowSysNotify { get; }\n        string Sounds { get; }\n        string SnapToWindow { get; }\n        string StartStopRecording { get; }\n        string StreamingKeys { get; }\n        string Timeout { get; }\n        string ToggleMouseClicks { get; }\n        string ToggleKeystrokes { get; }\n        string Tools { get; }\n        string Top { get; }\n        string TrayIcon { get; }\n        string Trim { get; }\n        string Undo { get; }\n        string UploadToImgur { get; }\n        string UseProxyAuth { get; }\n        string UserName { get; }\n        string VarFrameRate { get; }\n        string Video { get; }\n        string VideoEncoder { get; }\n        string VideoSaved { get; }\n        string VideoSource { get; }\n        string ViewCrashLogs { get; }\n        string ViewLicenses { get; }\n        string ViewOnGitHub { get; }\n        string WantToTranslate { get; }\n        string WebCam { get; }\n        string WebCamSeparateFile { get; }\n        string WebCamView { get; }\n        string Website { get; }\n        string Window { get; }\n        string WindowScreenShotTransparency { get; }\n        string Yes { get; }\n\n        event Action<CultureInfo> LanguageChanged;\n    }\n}"
  },
  {
    "path": "src/Captura.Loc/LanguageFields.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.Runtime.CompilerServices;\n// ReSharper disable MemberCanBePrivate.Global\n// ReSharper disable UnusedMember.Global\n\nnamespace Captura.Loc\n{\n    public class LanguageFields : NotifyPropertyChanged, ILocalizationProvider\n    {\n        protected virtual string GetValue(string Key) => \"\";\n\n        // ReSharper disable once VirtualMemberNeverOverridden.Global\n        // ReSharper disable UnusedParameter.Global\n        protected virtual void SetValue(string Key, string Value) { }\n        // ReSharper restore UnusedParameter.Global\n\n        string Get([CallerMemberName] string PropertyName = null)\n        {\n            return GetValue(PropertyName);\n        }\n\n        void Set(string Value, [CallerMemberName] string PropertyName = null)\n        {\n            SetValue(PropertyName, Value);\n\n            RaisePropertyChanged(PropertyName);\n        }\n\n        public virtual event Action<CultureInfo> LanguageChanged;\n\n        public string About\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string AccentColor\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Add\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string AlwaysOnTop\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Audio\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string AudioFormat\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string AudioSaved\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string BackColor\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string BorderColor\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string BorderThickness\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Bottom\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string CaptureDuration\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Center\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Changelog\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Clear\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ClearRecentList\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Clipboard\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Close\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Color\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ConfigCodecs\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Configure\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string CopyOutPathClipboard\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string CopyPath\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string CopyToClipboard\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string CornerRadius\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string CrashLogs\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Crop\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string CustomSize\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string CustomUrl\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string DarkTheme\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Delete\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string DiscardChanges\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Disk\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Donate\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string DownloadFFmpeg\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Edit\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Elapsed\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ErrorOccurred\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Exit\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FFmpegFolder\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FFmpegLog\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FileMenu\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FileMenuNew\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FileMenuOpen\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FileMenuSave\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FileNaming\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FontSize\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FrameRate\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string FullScreen\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string HideOnFullScreenShot\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Host\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Hotkeys\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ImageEditor\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ImgEmpty\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ImgFormat\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ImgSavedClipboard\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ImageUploadFailed\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ImageUploadSuccess\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ImageUploading\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string IncludeClicks\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string IncludeCursor\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string IncludeKeys\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Keymap\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Keystrokes\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string KeystrokesHistoryCount\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string KeystrokesHistorySpacing\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string KeystrokesSeparateFile\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Language\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Left\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string LoopbackSource\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MaxRecent\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MaxTextLength\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MicSource\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Minimize\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MinToTrayOnCaptureStart\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MinTray\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MinTrayStartup\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MinTrayClose\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MouseClicks\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MouseMiddleClickColor\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MousePointer\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string MouseRightClickColor\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string NewWindow\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string No\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string None\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Notifications\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string NotSaved\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string NoWebcam\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Ok\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string OnlyAudio\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Opacity\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string OpenFromClipboard\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string OpenOutFolder\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string OutFolder\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Overlays\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Padding\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Password\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Paused\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string PauseResume\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string PauseResumeRecording\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Port\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string PreStartCountdown\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Preview\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Proxy\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Quality\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Radius\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Recent\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string RecordStop\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Redo\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Refresh\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Region\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string RegionSelector\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string RemoveFromList\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Reset\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Resize\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string RestoreDefaults\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Right\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string SaveToClipboard\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Screen\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ScreenShot\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ScreenShotActiveWindow\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ScreenShotDesktop\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ScreenShotSaved\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string SelectFFmpegFolder\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string SelectOutFolder\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string SeparateAudioFiles\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ShowSysNotify\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Sounds\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string SnapToWindow\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string StartStopRecording\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string StreamingKeys\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Timeout\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ToggleMouseClicks\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ToggleKeystrokes\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Tools\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Top\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string TrayIcon\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Trim\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Undo\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string UploadToImgur\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string UseProxyAuth\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string UserName\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string VarFrameRate\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Video\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string VideoEncoder\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string VideoSaved\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string VideoSource\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ViewCrashLogs\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ViewLicenses\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string ViewOnGitHub\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string WantToTranslate\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string WebCam\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string WebCamSeparateFile\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string WebCamView\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Website\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Window\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string WindowScreenShotTransparency\n        {\n            get => Get();\n            set => Set(value);\n        }\n\n        public string Yes\n        {\n            get => Get();\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Loc/LanguageManager.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\nusing Newtonsoft.Json.Linq;\n\nnamespace Captura.Loc\n{\n    public class LanguageManager : LanguageFields\n    {\n        readonly JObject _defaultLanguage;\n        JObject _currentLanguage;\n        readonly string _langDir;\n        \n        public static LanguageManager Instance { get; } = new LanguageManager();\n\n        LanguageManager()\n        {\n            var appDir = ServiceProvider.AppDir;\n\n            var cultures = new List<CultureInfo>();\n\n            if (appDir != null)\n            {\n                _langDir = Path.Combine(appDir, \"Languages\");\n                \n                if (Directory.Exists(_langDir))\n                {\n                    foreach (var file in Directory.EnumerateFiles(_langDir, \"*.json\"))\n                    {\n                        var cultureName = Path.GetFileNameWithoutExtension(file);\n\n                        try\n                        {\n                            if (cultureName == null)\n                                continue;\n\n                            var culture = CultureInfo.GetCultureInfo(cultureName);\n\n                            cultures.Add(culture);\n                        }\n                        catch\n                        {\n                            // Ignore\n                        }\n                    }\n                }\n            }\n\n            _defaultLanguage = LoadLang(\"en\");\n\n            if (_currentCulture == null)\n                CurrentCulture = new CultureInfo(\"en\");\n\n            if (cultures.Count == 0)\n                cultures.Add(CurrentCulture);\n\n            cultures.Sort((X, Y) => string.Compare(X.DisplayName, Y.DisplayName, StringComparison.Ordinal));\n\n            AvailableCultures = cultures;\n        }\n\n        public IReadOnlyList<CultureInfo> AvailableCultures { get; }\n\n        CultureInfo _currentCulture;\n\n        public CultureInfo CurrentCulture\n        {\n            get => _currentCulture;\n            set\n            {\n                _currentCulture = value;\n\n                CultureInfo.CurrentUICulture = value;\n\n                _currentLanguage = LoadLang(value.Name);\n\n                LanguageChanged?.Invoke(value);\n\n                RaiseAllChanged();\n            }\n        }\n\n        public override event Action<CultureInfo> LanguageChanged;\n\n        JObject LoadLang(string LanguageId)\n        {\n            try\n            {\n                var filePath = Path.Combine(_langDir, $\"{LanguageId}.json\");\n\n                return JObject.Parse(File.ReadAllText(filePath));\n            }\n            catch\n            {\n                return new JObject();\n            }\n        }\n\n        public string this[string Key]\n        {\n            get\n            {\n                if (Key == null)\n                    return \"\";\n\n                if (_currentLanguage != null\n                    && _currentLanguage.TryGetValue(Key, out var value)\n                    && value.ToString() is string s\n                    && !string.IsNullOrWhiteSpace(s))\n                    return s;\n\n                if (_defaultLanguage != null\n                    && _defaultLanguage.TryGetValue(Key, out value)\n                    && value.ToString() is string t\n                    && !string.IsNullOrWhiteSpace(t))\n                    return t;\n\n                return Key;\n            }\n        }\n\n        protected override string GetValue(string PropertyName) => this[PropertyName];\n    }\n}\n"
  },
  {
    "path": "src/Captura.Loc/Languages/ar.json",
    "content": "{\n  \"About\": \"نبذة عن البرنامج\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"دائماً في الأعلى\",\n  \"Audio\": \"صوت\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"تم حفظ ملف الصوت\",\n  \"BackColor\": \"لون الخلفية\",\n  \"BorderColor\": \"لون الحدود\",\n  \"BorderThickness\": \"سمك الحدود\",\n  \"Bottom\": \"أسفل\",\n  \"CaptureDuration\": \"مدة الالتقاط (ثواني)\",\n  \"Center\": \"وسط\",\n  \"Changelog\": \"سجل التغييرات\",\n  \"Clear\": \"امسح\",\n  \"ClearRecentList\": \"امسح قائمة آخر الملفات\",\n  \"Clipboard\": \"الحافظة\",\n  \"Close\": \"اغلاق\",\n  \"Color\": \"لون\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"تهيئة\",\n  \"CopyOutPathClipboard\": \"انسخ مسار الإخراج إلى الحافظة\",\n  \"CopyPath\": \"انسخ المسار\",\n  \"CopyToClipboard\": \"انسخ إلى الحافظة\",\n  \"CornerRadius\": \"نصف قطر الركن\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"احذف\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"قرص\",\n  \"Donate\": \"تبرع\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"حدث خطأ\",\n  \"Exit\": \"خروج\",\n  \"FFmpegFolder\": \"مجلد FFmpeg\",\n  \"FFmpegLog\": \"سجل FFmpeg\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"حجم الخط\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"شاشة كاملة\",\n  \"HideOnFullScreenShot\": \"أخفي عند التقاط شاشة كاملة\",\n  \"Host\": \"مضيف\",\n  \"Hotkeys\": \"مفاتيح التشغيل السريع\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"لم يتم الحفظ. الصورة فارغة\",\n  \"ImgFormat\": \"نوع ملف الصورة\",\n  \"ImgSavedClipboard\": \"تم حفظ الصورة في الحافظة\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"تضمين نقرات الماوس\",\n  \"IncludeCursor\": \"تضمين المؤشر\",\n  \"IncludeKeys\": \"تضمين ضغطات المفاتيح\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"ضغطات المفاتيح\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"اللغة\",\n  \"Left\": \"يسار\",\n  \"LoopbackSource\": \"مصدر إخراج السماعة\",\n  \"MaxRecent\": \"عدد العناصر المحفوظة الأقصى\",\n  \"MaxTextLength\": \"طول النص الأقصى\",\n  \"MicSource\": \"مصدر الميكروفون\",\n  \"Minimize\": \"تصغير\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"تصغير إلى علبة النظام\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"نقرات الماوس\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"لا\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"لم يتم الحفظ\",\n  \"NoWebcam\": \"لا توجد كاميرا ويب\",\n  \"Ok\": \"موافق\",\n  \"OnlyAudio\": \"صوت فقط\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"افتح مجلد الإخراج\",\n  \"OutFolder\": \"مجلد الإخراج\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"كلمة المرور\",\n  \"Paused\": \"التسحيل متوقف\",\n  \"PauseResume\": \"توقف | متابعة\",\n  \"PauseResumeRecording\": \"أوقف/تابع التسجيل\",\n  \"Port\": \"منفذ\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"Proxy وكيل \",\n  \"Quality\": \"جودة\",\n  \"Radius\": \"نصف قطر\",\n  \"Recent\": \"الملفات الأخيرة\",\n  \"RecordStop\": \"تسجيل | توقف\",\n  \"Redo\": \"\",\n  \"Refresh\": \"تحديث\",\n  \"Region\": \"منطقة\",\n  \"RegionSelector\": \"انتقاء المنطقة\",\n  \"RemoveFromList\": \"احذف من القائمة\",\n  \"Reset\": \"إعادة تعيين\",\n  \"Resize\": \"تغيير الحجم\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"يمين\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"الشاشة\",\n  \"ScreenShot\": \"لقطة الشاشة\",\n  \"ScreenShotActiveWindow\": \"نافذة التقاط الشاشة النشطة\",\n  \"ScreenShotDesktop\": \"سطح مكتب التقاط الشاشة\",\n  \"ScreenShotSaved\": \"تم حفظ لقطة الشاشة\",\n  \"SelectFFmpegFolder\": \"اختر مجلد FFmpeg\",\n  \"SelectOutFolder\": \"اختر مجلد الإخراج\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"أظهر إعلامات علبة النظام\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"ابدأ/أوقف التسجيل\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"مهلة الانتظار\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"أعلى\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"استخدم مصادقة الوكيل\",\n  \"UserName\": \"اسم المستخدم\",\n  \"VarFrameRate\": \"معدل إطار متغير\",\n  \"Video\": \"فيديو\",\n  \"VideoEncoder\": \"أداة ترميز الفيديو\",\n  \"VideoSaved\": \"تم حفظ الفيديو\",\n  \"VideoSource\": \"مصدر الفيديو\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"هل تريد أن تترجم؟\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"منظر كاميرا الويب\",\n  \"Website\": \"\",\n  \"Window\": \"نافذة\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/be.json",
    "content": "{\n  \"About\": \"Інфа\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"Заўсёды на пярэднім плане\",\n  \"Audio\": \"Гук\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Гук захаваны\",\n  \"BackColor\": \"Колер фону\",\n  \"BorderColor\": \"Колер мяжы\",\n  \"BorderThickness\": \"Таўшчыня мяжы\",\n  \"Bottom\": \"Знізу\",\n  \"CaptureDuration\": \"Час захопу (у секундах)\",\n  \"Center\": \"Пасярэдзіне\",\n  \"Changelog\": \"Змена\",\n  \"Clear\": \"Ачысціць\",\n  \"ClearRecentList\": \"Ачысціць спіс\",\n  \"Clipboard\": \"Буфер абмену\",\n  \"Close\": \"Зачыніць\",\n  \"Color\": \"Колер\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Наладжваньне\",\n  \"CopyOutPathClipboard\": \"Капіяваць шлях да файла ў буфер абмену\",\n  \"CopyPath\": \"Шлях капіявання\",\n  \"CopyToClipboard\": \"Скапіяваць у буфер абмену\",\n  \"CornerRadius\": \"Радыус кутоў\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Выдаліць\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"Дыск\",\n  \"Donate\": \"Ахвяраваць\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"Адбылася памылка\",\n  \"Exit\": \"Выхад\",\n  \"FFmpegFolder\": \"Тэчка з FFmpeg\",\n  \"FFmpegLog\": \"Часопіс FFmpeg\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Памер шрыфта\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"Увесь экран\",\n  \"HideOnFullScreenShot\": \"Хаваць у поўнаэкранным рэжыме\",\n  \"Host\": \"Хост\",\n  \"Hotkeys\": \"Гарачыя клавішы\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Не захавана. Атрыманы малюнак пусты\",\n  \"ImgFormat\": \"Фармат малюнка\",\n  \"ImgSavedClipboard\": \"Малюнак захоўваецца ў буфер абмену\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Паказваць пстрычкі мышы\",\n  \"IncludeCursor\": \"Показывать курсор\",\n  \"IncludeKeys\": \"Паказваць націску клавіш\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"Націску клавіш\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Мова\",\n  \"Left\": \"Злева\",\n  \"LoopbackSource\": \"Прылада прайгравання гуку\",\n  \"MaxRecent\": \"Коль-ць элементаў\",\n  \"MaxTextLength\": \"Даўжыня тэксту\",\n  \"MicSource\": \"Крыніца гуку\",\n  \"Minimize\": \"Згарнуць\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Згарнуць у трэй\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"Пстрычкі мышы\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Не\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"Не захавана\",\n  \"NoWebcam\": \"\",\n  \"Ok\": \"\",\n  \"OnlyAudio\": \"Толькі гук\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"Адкрыць тэчку захавання\",\n  \"OutFolder\": \"Тэчка захавання\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Пароль\",\n  \"Paused\": \"Запіс прыпынены\",\n  \"PauseResume\": \"Прыпыніць | Аднавіць\",\n  \"PauseResumeRecording\": \"Паўза/старт запісу\",\n  \"Port\": \"Порт\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"Проксі\",\n  \"Quality\": \"Якасць\",\n  \"Radius\": \"Радыус\",\n  \"Recent\": \"Апошняе\",\n  \"RecordStop\": \"Пачаць запіс / спыніць запіс\",\n  \"Redo\": \"\",\n  \"Refresh\": \"Абнавіць\",\n  \"Region\": \"Вобласць экрана\",\n  \"RegionSelector\": \"Выбар вобласці захопу\",\n  \"RemoveFromList\": \"Выдаліць з спісу\",\n  \"Reset\": \"Скід\",\n  \"Resize\": \"Змяніць памер\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Справа\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Экран\",\n  \"ScreenShot\": \"Здымак экрана\",\n  \"ScreenShotActiveWindow\": \"Здымак актыўнага акна\",\n  \"ScreenShotDesktop\": \"Здымак працоўнага стала\",\n  \"ScreenShotSaved\": \"Здымак захаваны\",\n  \"SelectFFmpegFolder\": \"Паказаць тэчку\",\n  \"SelectOutFolder\": \"Вылучыце тэчку захавання\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Паказваць паведамлення ў трэі\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Старт/стоп запісу\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"Таймаўт\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"Зверху\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Уліковы запіс проксі\",\n  \"UserName\": \"Імя карыстальніка\",\n  \"VarFrameRate\": \"Переменная частота кадров\",\n  \"Video\": \"Відэа\",\n  \"VideoEncoder\": \"Відэакодэк\",\n  \"VideoSaved\": \"Відэа захавана\",\n  \"VideoSource\": \"Крыніца відэа\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Хочаце перавесці?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"Выгляд вэб-камеры\",\n  \"Website\": \"\",\n  \"Window\": \"Акно\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Так\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/ca.json",
    "content": "{\n  \"About\": \"En quant a\",\n  \"AccentColor\": \"Color d'èmfasi\",\n  \"Add\": \"Afegir\",\n  \"AlwaysOnTop\": \"Sempre a la part superior\",\n  \"Audio\": \"Àudio\",\n  \"AudioFormat\": \"Format d'àudio\",\n  \"AudioSaved\": \"Àudio desat\",\n  \"BackColor\": \"Color de fons\",\n  \"BorderColor\": \"Color del marge\",\n  \"BorderThickness\": \"Gruix del marge\",\n  \"Bottom\": \"Part inferior\",\n  \"CaptureDuration\": \"Durada de la captura (en segons)\",\n  \"Center\": \"Centre\",\n  \"Changelog\": \"Registre de canvis\",\n  \"Clear\": \"Esborrar\",\n  \"ClearRecentList\": \"Esborrar la llista recent\",\n  \"Clipboard\": \"Porta-retalls\",\n  \"Close\": \"Tancar\",\n  \"Color\": \"Color\",\n  \"ConfigCodecs\": \"Configurar els còdecs\",\n  \"Configure\": \"Configurar\",\n  \"CopyOutPathClipboard\": \"Copiar el camí del fitxer de sortida al porta-retalls\",\n  \"CopyPath\": \"Copiar camí\",\n  \"CopyToClipboard\": \"Copiar al porta-retalls\",\n  \"CornerRadius\": \"Radi del marge\",\n  \"CrashLogs\": \"Registre d'errors\",\n  \"Crop\": \"Retallar\",\n  \"CustomSize\": \"Tamany personalitzat\",\n  \"CustomUrl\": \"Adreça personalitzada\",\n  \"DarkTheme\": \"Tema fosc\",\n  \"Delete\": \"Eliminar\",\n  \"DiscardChanges\": \"Descartar canvis\",\n  \"Disk\": \"Disc\",\n  \"Donate\": \"Contribuir\",\n  \"DownloadFFmpeg\": \"Descarregar FFmpeg\",\n  \"Edit\": \"Editar\",\n  \"Elapsed\": \"Transcorregut\",\n  \"ErrorOccurred\": \"S'ha produït un error\",\n  \"Exit\": \"Sortir\",\n  \"FFmpegFolder\": \"Carpeta FFmpeg\",\n  \"FFmpegLog\": \"Registre FFmpeg\",\n  \"FileMenu\": \"Fitxer\",\n  \"FileMenuNew\": \"Nou\",\n  \"FileMenuOpen\": \"Obrir\",\n  \"FileMenuSave\": \"Desar\",\n  \"FileNaming\": \"Donar un nom\",\n  \"FontSize\": \"Tamany de fonts\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Pantalla completa\",\n  \"HideOnFullScreenShot\": \"Amagar durant la captura de pantalla completa\",\n  \"Host\": \"Host\",\n  \"Hotkeys\": \"Tecles ràpides\",\n  \"ImageEditor\": \"Editor d’imatges\",\n  \"ImgEmpty\": \"No desat. La imatge capturada és buida\",\n  \"ImgFormat\": \"Format d'imatge\",\n  \"ImgSavedClipboard\": \"Imatge desada al porta-retalls\",\n  \"ImageUploadFailed\": \"La càrrega de la imatge ha fallat\",\n  \"ImageUploadSuccess\": \"Imatge carregada correctament\",\n  \"ImageUploading\": \"Carregant imatges\",\n  \"IncludeClicks\": \"Incloure els clics del ratolí\",\n  \"IncludeCursor\": \"Incloure el cursor\",\n  \"IncludeKeys\": \"Incloure les pulsacions de tecla\",\n  \"Keymap\": \"Mapa de tecles\",\n  \"Keystrokes\": \"Pulsacions de tecla\",\n  \"KeystrokesHistoryCount\": \"Comptador històric\",\n  \"KeystrokesHistorySpacing\": \"Històric d'espaiat\",\n  \"KeystrokesSeparateFile\": \"Desa en un fitxer de text separat\",\n  \"Language\": \"Idioma\",\n  \"Left\": \"Esquerra\",\n  \"LoopbackSource\": \"Altaveus de sortida\",\n  \"MaxRecent\": \"Elements màxims per recordar\",\n  \"MaxTextLength\": \"Longitud màxima del text\",\n  \"MicSource\": \"Micròfon origen\",\n  \"Minimize\": \"Minimitzar\",\n  \"MinToTrayOnCaptureStart\": \"Minimitzar a la safata del sistema al capturar\",\n  \"MinTray\": \"Minimitza a la safata de sistema\",\n  \"MinTrayStartup\": \"Minimitzar a la safata del sistema a l'inici\",\n  \"MinTrayClose\": \"Minimitzar a la safata del sistema al tancar\",\n  \"MouseClicks\": \"Clics del ratolí\",\n  \"MouseMiddleClickColor\": \"Color del clic mitjà\",\n  \"MousePointer\": \"Punter del ratolí\",\n  \"MouseRightClickColor\": \"Color del clic dret\",\n  \"NewWindow\": \"Nova finestra\",\n  \"No\": \"No\",\n  \"None\": \"Cap\",\n  \"Notifications\": \"Notificacions\",\n  \"NotSaved\": \"No s'ha desat\",\n  \"NoWebcam\": \"Sense Webcam\",\n  \"Ok\": \"D'acord\",\n  \"OnlyAudio\": \"Només àudio\",\n  \"Opacity\": \"Opacitat\",\n  \"OpenFromClipboard\": \"Obrir des del porta-retalls\",\n  \"OpenOutFolder\": \"Obrir la carpeta de sortida\",\n  \"OutFolder\": \"Carpeta de sortida\",\n  \"Overlays\": \"Superposar\",\n  \"Padding\": \"Omplir\",\n  \"Password\": \"Clau d'accés\",\n  \"Paused\": \"Gravació en pausa\",\n  \"PauseResume\": \"Pausar | Continuar\",\n  \"PauseResumeRecording\": \"Pausar/Continuar gravant\",\n  \"Port\": \"Port\",\n  \"Preview\": \"Vista prèvia\",\n  \"PreStartCountdown\": \"Compte enrere abans de començar (segons)\",\n  \"Proxy\": \"Servidor intermediari\",\n  \"Quality\": \"Qualitat\",\n  \"Radius\": \"Radi\",\n  \"Recent\": \"Recent\",\n  \"RecordStop\": \"Gravar | Aturar\",\n  \"Redo\": \"Refer\",\n  \"Refresh\": \"Refrescar\",\n  \"Region\": \"Regió\",\n  \"RegionSelector\": \"Selector de regió\",\n  \"RemoveFromList\": \"Eliminar de la llista\",\n  \"Reset\": \"Restablir\",\n  \"Resize\": \"Redimensionar\",\n  \"RestoreDefaults\": \"Restaurar valors predeterminats\",\n  \"Right\": \"Dreta\",\n  \"SaveToClipboard\": \"Desar al porta-retalls\",\n  \"Screen\": \"Pantalla\",\n  \"ScreenShot\": \"Captura de pantalla\",\n  \"ScreenShotActiveWindow\": \"Capturar la finestra activa\",\n  \"ScreenShotDesktop\": \"Capturar l'escriptori\",\n  \"ScreenShotSaved\": \"Captura de pantalla desada\",\n  \"SelectFFmpegFolder\": \"Seleccionar la carpeta FFmpeg\",\n  \"SelectOutFolder\": \"Seleccionar la carpeta de sortida\",\n  \"SeparateAudioFiles\": \"Fitxers separats per a cada font d'àudio\",\n  \"ShowSysNotify\": \"Mostra les notificacions de la safata del sistema\",\n  \"SnapToWindow\": \"Capturar a la finestra\",\n  \"Sounds\": \"Àudios\",\n  \"StartStopRecording\": \"Iniciar/Aturar la gravació\",\n  \"StreamingKeys\": \"Tecles de reproducció\",\n  \"Timeout\": \"Temps d'espera\",\n  \"ToggleMouseClicks\": \"Commutar els clics del ratolí\",\n  \"ToggleKeystrokes\": \"Commutar les pulsacions de tecles\",\n  \"Tools\": \"Eines\",\n  \"Top\": \"Part superior\",\n  \"TrayIcon\": \"Safata del sistema\",\n  \"Trim\": \"Retallar\",\n  \"Undo\": \"Desfer\",\n  \"UploadToImgur\": \"Carregar a Imgur\",\n  \"UseProxyAuth\": \"Utilitzar un servidor intermediari d'autenticació\",\n  \"UserName\": \"Nom d'usuari\",\n  \"VarFrameRate\": \"Fotogrames variables\",\n  \"Video\": \"Vídeo\",\n  \"VideoEncoder\": \"Codificador de vídeo\",\n  \"VideoSaved\": \"Vídeo desat\",\n  \"VideoSource\": \"Font de vídeo\",\n  \"ViewCrashLogs\": \"Veure el registre d'errors\",\n  \"ViewLicenses\": \"Veure llicències\",\n  \"ViewOnGitHub\": \"Veure a GitHub\",\n  \"WantToTranslate\": \"Voleu traduir?\",\n  \"WebCam\": \"Webcam\",\n  \"WebCamSeparateFile\": \"Gravació de Webcam en fitxer separat\",\n  \"WebCamView\": \"Veure WebCam\",\n  \"Website\": \"Lloc web\",\n  \"Window\": \"Finestra\",\n  \"WindowScreenShotTransparency\": \"Les captures de pantalla en mode finestra haurien de ser transparents\",\n  \"Yes\": \"Sí\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/cs.json",
    "content": "{\n  \"About\": \"O Aplikaci\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"Vždy Navrchu\",\n  \"Audio\": \"Zvuk\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Zvuk Uložen\",\n  \"BackColor\": \"Barva Pozadí\",\n  \"BorderColor\": \"Barva Okraje\",\n  \"BorderThickness\": \"Šířka okraje\",\n  \"Bottom\": \"Dolů\",\n  \"CaptureDuration\": \"Délka Záznamu (v sekundách)\",\n  \"Center\": \"Vycentrovat\",\n  \"Changelog\": \"Seznam změn\",\n  \"Clear\": \"Vymazat\",\n  \"ClearRecentList\": \"Vymazat Aktuální Seznam\",\n  \"Clipboard\": \"Schránka\",\n  \"Close\": \"Zavřít\",\n  \"Color\": \"Barva\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Konfigurovat\",\n  \"CopyOutPathClipboard\": \"Kopírovat cestu k souboru do Schránky\",\n  \"CopyPath\": \"Kopírovat cestu\",\n  \"CopyToClipboard\": \"Kopírovat do schránky\",\n  \"CornerRadius\": \"Zakulacení Rohů\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Smazat\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"\",\n  \"Donate\": \"Darovat\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"Nastala Chyba\",\n  \"Exit\": \"Ukončit\",\n  \"FFmpegFolder\": \"FFmpeg Složka\",\n  \"FFmpegLog\": \"\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Velikost Fontu\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"Celá Obrazovka\",\n  \"HideOnFullScreenShot\": \"Skrýt při záznamu Celé Obrazovky\",\n  \"Host\": \"\",\n  \"Hotkeys\": \"Horké klávesy\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Neuloženo. Sejmutý obrázek byl Prázdný.\",\n  \"ImgFormat\": \"Formát Obrázku\",\n  \"ImgSavedClipboard\": \"Obrázek Uložen do Schránky\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Zahrnout Kliknutí Myši\",\n  \"IncludeCursor\": \"Zahrnout Kurzor\",\n  \"IncludeKeys\": \"Zahrnout Stisky kláves\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"Stisky kláves\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Jazyk\",\n  \"Left\": \"Vlevo\",\n  \"LoopbackSource\": \"Vstup pro reproduktor\",\n  \"MaxRecent\": \"Maximum položek k uchování\",\n  \"MaxTextLength\": \"Maximální délka textu\",\n  \"MicSource\": \"Vstup pro mikrofón\",\n  \"Minimize\": \"Minimalizovat\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Minimalizovat do systémové lišty\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"Kliknutí Myši\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Ne\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"Neuloženo\",\n  \"NoWebcam\": \"Bez Webové Kamery\",\n  \"Ok\": \"\",\n  \"OnlyAudio\": \"Pouze Zvuk\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"Otevřít složku pro uložení\",\n  \"OutFolder\": \"Složka pro uložení\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Heslo\",\n  \"Paused\": \"Nahrávání Pozastaveno\",\n  \"PauseResume\": \"Zastavit | Obnovit\",\n  \"PauseResumeRecording\": \"Zastavit/Obnovit Nahrávání\",\n  \"Port\": \"\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"\",\n  \"Quality\": \"Kvalita\",\n  \"Radius\": \"Poloměr\",\n  \"Recent\": \"Nedávné\",\n  \"RecordStop\": \"Nahrát | Zastavit\",\n  \"Redo\": \"\",\n  \"Refresh\": \"Obnovit\",\n  \"Region\": \"\",\n  \"RegionSelector\": \"Výběr Regionu\",\n  \"RemoveFromList\": \"Odstranit ze Seznamu\",\n  \"Reset\": \"Resetovat\",\n  \"Resize\": \"Změnit Velikost\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Vpravo\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Obrazovka\",\n  \"ScreenShot\": \"\",\n  \"ScreenShotActiveWindow\": \"ScreenShot Aktivní okno\",\n  \"ScreenShotDesktop\": \"ScreenShot Plochu\",\n  \"ScreenShotSaved\": \"ScreenShot Uložen\",\n  \"SelectFFmpegFolder\": \"Vyber Složku FFmpeg\",\n  \"SelectOutFolder\": \"Vyber Složku pro výstup\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Zobrazit Ikonu v systémové liště\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Start/Stop Nahrávání\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"Přestávka\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"Nahoru\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Použít Proxy Autentifikaci\",\n  \"UserName\": \"Uživatelské Jméno\",\n  \"VarFrameRate\": \"Proměnný Frame Rate\",\n  \"Video\": \"\",\n  \"VideoEncoder\": \"\",\n  \"VideoSaved\": \"Video Uloženo\",\n  \"VideoSource\": \"Zdroj Videa\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Přeložit?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"Zobrazení webové kamery\",\n  \"Website\": \"\",\n  \"Window\": \"Okno\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Ano\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/da.json",
    "content": "{\n  \"About\": \"Om\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"Altid øverst\",\n  \"Audio\": \"Lyd\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Lyd gemt\",\n  \"BackColor\": \"Baggrundsfarve\",\n  \"BorderColor\": \"Kantfarve\",\n  \"BorderThickness\": \"Kanttykkelse\",\n  \"Bottom\": \"Bund\",\n  \"CaptureDuration\": \"Optagevarighed (i sekunder)\",\n  \"Center\": \"Midten\",\n  \"Changelog\": \"Ændringshistorik\",\n  \"Clear\": \"Ryd\",\n  \"ClearRecentList\": \"Ryd senest åbnede\",\n  \"Clipboard\": \"Udklipsholder\",\n  \"Close\": \"Luk\",\n  \"Color\": \"Farve\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Konfigurere\",\n  \"CopyOutPathClipboard\": \"Kopier output-filsti til udklipsholder\",\n  \"CopyPath\": \"Kopisti\",\n  \"CopyToClipboard\": \"Kopier til udklipsholder\",\n  \"CornerRadius\": \"Hjørneradius\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Slet\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"Harddisk\",\n  \"Donate\": \"Donere\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"En fejl opstod\",\n  \"Exit\": \"Afslut\",\n  \"FFmpegFolder\": \"FFmpeg-mappe\",\n  \"FFmpegLog\": \"FFmpeg-log\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Skriftstørrelse\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"Fuld skærm\",\n  \"HideOnFullScreenShot\": \"Skjul ved skærmbillede i fuld skærm\",\n  \"Host\": \"Vært\",\n  \"Hotkeys\": \"Genvejstaster\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Ikke gemt. Billedet var tomt.\",\n  \"ImgFormat\": \"Billedformat\",\n  \"ImgSavedClipboard\": \"Billede blev gemt i udklipsholder\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Inkluder museklik\",\n  \"IncludeCursor\": \"Inkluder musemarkør\",\n  \"IncludeKeys\": \"Inkluder tastetryk\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"Tastetryk\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Sprog\",\n  \"Left\": \"Venstre\",\n  \"LoopbackSource\": \"Lyd-kilde\",\n  \"MaxRecent\": \"Maks. antal filer\",\n  \"MaxTextLength\": \"Maks. tekstlængde\",\n  \"MicSource\": \"Mikrofon-kilde\",\n  \"Minimize\": \"Minimer\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Minimer til systembakken\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"Museklik\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Nej\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"Ikke gemt\",\n  \"NoWebcam\": \"Intet webkamera\",\n  \"Ok\": \"Ok\",\n  \"OnlyAudio\": \"Kun lyd\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"Åben output-mappe\",\n  \"OutFolder\": \"Output-mappe\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Kodeord\",\n  \"Paused\": \"Optagelse pauset\",\n  \"PauseResume\": \"Pause | Fortsæt\",\n  \"PauseResumeRecording\": \"Pause/Fortsæt optagelse\",\n  \"Port\": \"\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"\",\n  \"Quality\": \"Kvalitet\",\n  \"Radius\": \"\",\n  \"Recent\": \"Senest\",\n  \"RecordStop\": \"Optag | Stop\",\n  \"Redo\": \"\",\n  \"Refresh\": \"Opdater\",\n  \"Region\": \"\",\n  \"RegionSelector\": \"Vælg region\",\n  \"RemoveFromList\": \"Fjern fra liste\",\n  \"Reset\": \"Nulstil\",\n  \"Resize\": \"Tilpas størrelse\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Højre\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Skærm\",\n  \"ScreenShot\": \"Skærmbillede\",\n  \"ScreenShotActiveWindow\": \"Skærmbillede af aktivt vindue\",\n  \"ScreenShotDesktop\": \"Skærmbillede af skrivbord\",\n  \"ScreenShotSaved\": \"Skærmbillede gemt\",\n  \"SelectFFmpegFolder\": \"Velg FFmpeg-mappe\",\n  \"SelectOutFolder\": \"Velg output-mappe\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Vis systembakke-notifikationer\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Start/Stop optagelse\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Anvend proxy-autentifikation\",\n  \"UserName\": \"Brugernavn\",\n  \"VarFrameRate\": \"Variabel billedhastighed\",\n  \"Video\": \"\",\n  \"VideoEncoder\": \"Video-encoder\",\n  \"VideoSaved\": \"Video gemt\",\n  \"VideoSource\": \"Video-kilde\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Vil du oversætte?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"Webkamera-visning\",\n  \"Website\": \"\",\n  \"Window\": \"Vindue\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Ja\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/de.json",
    "content": "{\n  \"About\": \"Über\",\n  \"AccentColor\": \"Akzentfarbe\",\n  \"Add\": \"Hinzufügen\",\n  \"AlwaysOnTop\": \"Immer im Vordergrund\",\n  \"Audio\": \"Audio\",\n  \"AudioFormat\": \"Audioformat\",\n  \"AudioSaved\": \"Audio gespeichert\",\n  \"BackColor\": \"Hintergrundfarbe\",\n  \"BorderColor\": \"Rahmenfarbe\",\n  \"BorderThickness\": \"Rahmendicke\",\n  \"Bottom\": \"Unten\",\n  \"CaptureDuration\": \"Aufnahmedauer (in Sekunden)\",\n  \"Center\": \"Mitte\",\n  \"Changelog\": \"Neuerungen\",\n  \"Clear\": \"Leeren\",\n  \"ClearRecentList\": \"Liste leeren\",\n  \"Clipboard\": \"Zwischenablage\",\n  \"Close\": \"Schließen\",\n  \"Color\": \"Farbe\",\n  \"ConfigCodecs\": \"Codecs konfigurieren\",\n  \"Configure\": \"Einstellungen\",\n  \"CopyOutPathClipboard\": \"Pfad zur Ausgabedatei in Zwischenablage kopieren\",\n  \"CopyPath\": \"Pfad kopieren\",\n  \"CopyToClipboard\": \"In Zwischenablage kopieren\",\n  \"CornerRadius\": \"Eckenradius\",\n  \"CrashLogs\": \"Fehlerprotokolle\",\n  \"Crop\": \"Zuschneiden\",\n  \"CustomSize\": \"Größe anpassen\",\n  \"CustomUrl\": \"Eigene Url\",\n  \"DarkTheme\": \"Dunkles Design\",\n  \"Delete\": \"Löschen\",\n  \"DiscardChanges\": \"Änderungen verwerfen\",\n  \"Disk\": \"Festplatte\",\n  \"Donate\": \"Spenden\",\n  \"DownloadFFmpeg\": \"FFmpeg herunterladen\",\n  \"Edit\": \"Bearbeiten\",\n  \"Elapsed\": \"Aufnahmedauer aufnehmen\",\n  \"ErrorOccurred\": \"Ein Fehler ist aufgetreten\",\n  \"Exit\": \"Beenden\",\n  \"FFmpegFolder\": \"FFmpeg Verzeichnis\",\n  \"FFmpegLog\": \"FFmpeg-Log\",\n  \"FileMenu\": \"Datei\",\n  \"FileMenuNew\": \"Neu\",\n  \"FileMenuOpen\": \"Öffnen\",\n  \"FileMenuSave\": \"Speichern\",\n  \"FileNaming\": \"Dateiname\",\n  \"FontSize\": \"Schriftgröße\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Alle Bildschirme\",\n  \"HideOnFullScreenShot\": \"Anwendung bei Screenshot des gesamten Bildschirms verstecken\",\n  \"Host\": \"Host\",\n  \"Hotkeys\": \"Hotkeys\",\n  \"ImageEditor\": \"Fotoeditor\",\n  \"ImgEmpty\": \"Das Bild wurde nicht gespeichert. Kein Inhalt\",\n  \"ImgFormat\": \"Bildformat\",\n  \"ImgSavedClipboard\": \"Bild in die Zwischenablage gespeichert\",\n  \"ImageUploadFailed\": \"Das Hochladen des Fotos ist fehlgeschlagen\",\n  \"ImageUploadSuccess\": \"Das Bild wurde erfolgreich hochgeladen\",\n  \"ImageUploading\": \"Bild wird hochgeladen\",\n  \"IncludeClicks\": \"Mausklicks aufnehmen\",\n  \"IncludeCursor\": \"Mauszeiger aufnehmen\",\n  \"IncludeKeys\": \"Tastenanschläge aufnehmen\",\n  \"Keymap\": \"Tastenbelegung\",\n  \"Keystrokes\": \"Tastenanschläge\",\n  \"KeystrokesHistoryCount\": \"Anzahl der Historieneinträge\",\n  \"KeystrokesHistorySpacing\": \"Historien-Abstand\",\n  \"KeystrokesSeparateFile\": \"In separater Textdatei speichern\",\n  \"Language\": \"Sprache\",\n  \"Left\": \"Links\",\n  \"LoopbackSource\": \"Audio Ausgabequelle\",\n  \"MaxRecent\": \"Maximale Anzahl Einträge\",\n  \"MaxTextLength\": \"Max. Textlänge\",\n  \"MicSource\": \"Audio Eingabequelle\",\n  \"Minimize\": \"Minimieren\",\n  \"MinToTrayOnCaptureStart\": \"Bei Aufnahmestart in den System Tray minimieren\",\n  \"MinTray\": \"In Tray minimieren\",\n  \"MinTrayStartup\": \"Programm minimiert starten\",\n  \"MinTrayClose\": \"Fenster beim Schließen minimieren\",\n  \"MouseClicks\": \"Mausklicks\",\n  \"MouseMiddleClickColor\": \"Farbe für mittleren Mausklick\",\n  \"MousePointer\": \"Mauszeiger\",\n  \"MouseRightClickColor\": \"Farbe für rechten Mausklick\",\n  \"NewWindow\": \"Neues Fenster\",\n  \"No\": \"Nein\",\n  \"None\": \"Kein/e/s\",\n  \"Notifications\": \"Benachrichtigungen\",\n  \"NotSaved\": \"Nicht gespeichert\",\n  \"NoWebcam\": \"Keine Webcam\",\n  \"Ok\": \"OK\",\n  \"OnlyAudio\": \"Nur Audio\",\n  \"Opacity\": \"Transparenz\",\n  \"OpenFromClipboard\": \"Aus Zwischenablage einfügen\",\n  \"OpenOutFolder\": \"Ausgabeordner öffnen\",\n  \"OutFolder\": \"Ausgabeordner\",\n  \"Overlays\": \"Bildüberlagerung\",\n  \"Padding\": \"Abstand\",\n  \"Password\": \"Passwort\",\n  \"Paused\": \"Aufnahme pausiert\",\n  \"PauseResume\": \"Pause | Fortsetzen\",\n  \"PauseResumeRecording\": \"Aufnahme pausieren/fortsetzen\",\n  \"Port\": \"Port\",\n  \"Preview\": \"Vorschau\",\n  \"PreStartCountdown\": \"Countdown vor dem Start (Sekunden)\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Qualität\",\n  \"Radius\": \"Radius\",\n  \"Recent\": \"Letzte Aufnahmen\",\n  \"RecordStop\": \"Aufnehmen | Stopp\",\n  \"Redo\": \"Wiederherstellen\",\n  \"Refresh\": \"Aktualisieren\",\n  \"Region\": \"Region\",\n  \"RegionSelector\": \"Regionsauswahl\",\n  \"RemoveFromList\": \"Aus Liste löschen\",\n  \"Reset\": \"Zurücksetzen\",\n  \"Resize\": \"Größe ändern\",\n  \"RestoreDefaults\": \"Standardeinstellungen wiederherstellen\",\n  \"Right\": \"Rechts\",\n  \"SaveToClipboard\": \"In die Zwischenablage kopieren\",\n  \"Screen\": \"Bildschirm\",\n  \"ScreenShot\": \"Bildschirmfoto\",\n  \"ScreenShotActiveWindow\": \"Bildschirmfoto Aktives Fenster\",\n  \"ScreenShotDesktop\": \"Bildschirmfoto des Desktops\",\n  \"ScreenShotSaved\": \"Bildschirmfoto gespeichert\",\n  \"SelectFFmpegFolder\": \"FFmpeg Ordner auswählen\",\n  \"SelectOutFolder\": \"Ausgabeordner auswählen\",\n  \"SeparateAudioFiles\": \"Separate Datei für jede Audio-Quelle\",\n  \"ShowSysNotify\": \"System Tray Benachrichtigungen anzeigen\",\n  \"SnapToWindow\": \"An Fenstergröße anpassen\",\n  \"Sounds\": \"Klänge\",\n  \"StartStopRecording\": \"Aufnahme starten/stoppen\",\n  \"StreamingKeys\": \"Streaming-Tasten\",\n  \"Timeout\": \"Zeitüberschreitung\",\n  \"ToggleMouseClicks\": \"Mausklicks anzeigen/ausblenden\",\n  \"ToggleKeystrokes\": \"Tastaturanschläge anzeigen/ausblenden\",\n  \"Tools\": \"Werkzeuge\",\n  \"Top\": \"Oben\",\n  \"TrayIcon\": \"Symbol in der Taskleiste\",\n  \"Trim\": \"Kürzen\",\n  \"Undo\": \"Rückgängig\",\n  \"UploadToImgur\": \"Zu Imgur hochladen\",\n  \"UseProxyAuth\": \"Proxy Authentifizierung verwenden\",\n  \"UserName\": \"Benutzername\",\n  \"VarFrameRate\": \"Variable Bildwiederholrate\",\n  \"Video\": \"Video\",\n  \"VideoEncoder\": \"Video Encoder\",\n  \"VideoSaved\": \"Video gespeichert\",\n  \"VideoSource\": \"Video Quelle\",\n  \"ViewCrashLogs\": \"Absturzberichte anzeigen\",\n  \"ViewLicenses\": \"Lizenz ansehen\",\n  \"ViewOnGitHub\": \"Auf GitHub anzeigen\",\n  \"WantToTranslate\": \"Wollen Sie bei der Übersetzung helfen?\",\n  \"WebCam\": \"Webcam\",\n  \"WebCamSeparateFile\": \"Webcam-Video als separate Datei aufnehmen\",\n  \"WebCamView\": \"WebCam-Ansicht\",\n  \"Website\": \"Webseite\",\n  \"Window\": \"Fenster\",\n  \"WindowScreenShotTransparency\": \"Transparenz bei Fenster-Screenshots beibehalten\",\n  \"Yes\": \"Ja\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/el.json",
    "content": "{\n  \"About\": \"\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"\",\n  \"Audio\": \"\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"\",\n  \"BackColor\": \"\",\n  \"BorderColor\": \"\",\n  \"BorderThickness\": \"\",\n  \"Bottom\": \"\",\n  \"CaptureDuration\": \"\",\n  \"Center\": \"\",\n  \"Changelog\": \"\",\n  \"Clear\": \"\",\n  \"ClearRecentList\": \"\",\n  \"Clipboard\": \"\",\n  \"Close\": \"\",\n  \"Color\": \"\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"\",\n  \"CopyOutPathClipboard\": \"\",\n  \"CopyPath\": \"\",\n  \"CopyToClipboard\": \"\",\n  \"CornerRadius\": \"\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"\",\n  \"Donate\": \"\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"\",\n  \"Exit\": \"\",\n  \"FFmpegFolder\": \"\",\n  \"FFmpegLog\": \"\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"\",\n  \"HideOnFullScreenShot\": \"\",\n  \"Host\": \"\",\n  \"Hotkeys\": \"\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"\",\n  \"ImgFormat\": \"\",\n  \"ImgSavedClipboard\": \"\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"\",\n  \"IncludeCursor\": \"\",\n  \"IncludeKeys\": \"\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"\",\n  \"Left\": \"\",\n  \"LoopbackSource\": \"\",\n  \"MaxRecent\": \"\",\n  \"MaxTextLength\": \"\",\n  \"MicSource\": \"\",\n  \"Minimize\": \"\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"\",\n  \"NoWebcam\": \"\",\n  \"Ok\": \"\",\n  \"OnlyAudio\": \"\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"\",\n  \"OutFolder\": \"\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"\",\n  \"Paused\": \"\",\n  \"PauseResume\": \"\",\n  \"PauseResumeRecording\": \"\",\n  \"Port\": \"\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"\",\n  \"Quality\": \"\",\n  \"Radius\": \"\",\n  \"Recent\": \"\",\n  \"RecordStop\": \"\",\n  \"Redo\": \"\",\n  \"Refresh\": \"\",\n  \"Region\": \"\",\n  \"RegionSelector\": \"\",\n  \"RemoveFromList\": \"\",\n  \"Reset\": \"\",\n  \"Resize\": \"\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"\",\n  \"ScreenShot\": \"\",\n  \"ScreenShotActiveWindow\": \"\",\n  \"ScreenShotDesktop\": \"\",\n  \"ScreenShotSaved\": \"\",\n  \"SelectFFmpegFolder\": \"\",\n  \"SelectOutFolder\": \"\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"\",\n  \"UserName\": \"\",\n  \"VarFrameRate\": \"\",\n  \"Video\": \"\",\n  \"VideoEncoder\": \"\",\n  \"VideoSaved\": \"\",\n  \"VideoSource\": \"\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"\",\n  \"Website\": \"\",\n  \"Window\": \"\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/en.json",
    "content": "{\n  \"About\": \"About\",\n  \"AccentColor\": \"Accent Color\",\n  \"Add\": \"Add\",\n  \"AlwaysOnTop\": \"Always on Top\",\n  \"Audio\": \"Audio\",\n  \"AudioFormat\": \"Audio Format\",\n  \"AudioSaved\": \"Audio Saved\",\n  \"BackColor\": \"Back Color\",\n  \"BorderColor\": \"Border Color\",\n  \"BorderThickness\": \"Border Thickness\",\n  \"Bottom\": \"Bottom\",\n  \"CaptureDuration\": \"Capture Duration (in seconds)\",\n  \"Center\": \"Center\",\n  \"Changelog\": \"Changelog\",\n  \"Clear\": \"Clear\",\n  \"ClearRecentList\": \"Clear Recent List\",\n  \"Clipboard\": \"Clipboard\",\n  \"Close\": \"Close\",\n  \"Color\": \"Color\",\n  \"ConfigCodecs\": \"Configure Codecs\",\n  \"Configure\": \"Configure\",\n  \"CopyOutPathClipboard\": \"Copy Output file path to Clipboard\",\n  \"CopyPath\": \"Copy Path\",\n  \"CopyToClipboard\": \"Copy to Clipboard\",\n  \"CornerRadius\": \"Corner Radius\",\n  \"CrashLogs\": \"Crash Logs\",\n  \"Crop\": \"Crop\",\n  \"CustomSize\": \"Custom Size\",\n  \"CustomUrl\": \"Custom Url\",\n  \"DarkTheme\": \"Dark Theme\",\n  \"Delete\": \"Delete\",\n  \"DiscardChanges\": \"Discard Changes\",\n  \"Disk\": \"Disk\",\n  \"Donate\": \"Donate\",\n  \"DownloadFFmpeg\": \"Download FFmpeg\",\n  \"Edit\": \"Edit\",\n  \"Elapsed\": \"Elapsed\",\n  \"ErrorOccurred\": \"An Error Occurred\",\n  \"Exit\": \"Exit\",\n  \"FFmpegFolder\": \"FFmpeg Folder\",\n  \"FFmpegLog\": \"FFmpeg Log\",\n  \"FileMenu\": \"File\",\n  \"FileMenuNew\": \"New\",\n  \"FileMenuOpen\": \"Open\",\n  \"FileMenuSave\": \"Save\",\n  \"FileNaming\": \"File Naming\",\n  \"FontSize\": \"Font Size\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Full Screen\",\n  \"HideOnFullScreenShot\": \"Hide on Full Screen ScreenShot\",\n  \"Host\": \"Host\",\n  \"Hotkeys\": \"Hotkeys\",\n  \"ImageEditor\": \"Image Editor\",\n  \"ImgEmpty\": \"Not Saved. Image taken was Empty\",\n  \"ImgFormat\": \"Image Format\",\n  \"ImgSavedClipboard\": \"Image Saved to Clipboard\",\n  \"ImageUploadFailed\": \"Image Upload Failed\",\n  \"ImageUploadSuccess\": \"Image Upload Successful\",\n  \"ImageUploading\": \"Uploading Image\",\n  \"IncludeClicks\": \"Include Mouse Clicks\",\n  \"IncludeCursor\": \"Include Cursor\",\n  \"IncludeKeys\": \"Include KeyStrokes\",\n  \"Keymap\": \"Keymap\",\n  \"Keystrokes\": \"Keystrokes\",\n  \"KeystrokesHistoryCount\": \"History Count\",\n  \"KeystrokesHistorySpacing\": \"History Spacing\",\n  \"KeystrokesSeparateFile\": \"Save to separate Text file\",\n  \"Language\": \"Language\",\n  \"Left\": \"Left\",\n  \"LoopbackSource\": \"Speaker Output Source\",\n  \"MaxRecent\": \"Max items to persist\",\n  \"MaxTextLength\": \"Max Text Length\",\n  \"MicSource\": \"Microphone Source\",\n  \"Minimize\": \"Minimize\",\n  \"MinToTrayOnCaptureStart\": \"Minimize to Tray on Capture Start\",\n  \"MinTray\": \"Minimize to System Tray\",\n  \"MinTrayStartup\": \"Minimize to Tray on Startup\",\n  \"MinTrayClose\": \"Minimize to Tray when Closed\",\n  \"MouseClicks\": \"Mouse Clicks\",\n  \"MouseMiddleClickColor\": \"Middle Click Color\",\n  \"MousePointer\": \"Mouse Pointer\",\n  \"MouseRightClickColor\": \"Right Click Color\",\n  \"NewWindow\": \"NewWindow\",\n  \"No\": \"No\",\n  \"None\": \"None\",\n  \"Notifications\": \"Notifications\",\n  \"NotSaved\": \"Not Saved\",\n  \"NoWebcam\": \"No Webcam\",\n  \"Ok\": \"OK\",\n  \"OnlyAudio\": \"Only Audio\",\n  \"Opacity\": \"Opacity\",\n  \"OpenFromClipboard\": \"Open from Clipboard\",\n  \"OpenOutFolder\": \"Open Output Folder\",\n  \"OutFolder\": \"Output Folder\",\n  \"Overlays\": \"Overlays\",\n  \"Padding\": \"Padding\",\n  \"Password\": \"Password\",\n  \"Paused\": \"Recording Paused\",\n  \"PauseResume\": \"Pause | Resume\",\n  \"PauseResumeRecording\": \"Pause/Resume Recording\",\n  \"Port\": \"Port\",\n  \"Preview\": \"Preview\",\n  \"PreStartCountdown\": \"Pre Start Countdown (seconds)\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Quality\",\n  \"Radius\": \"Radius\",\n  \"Recent\": \"Recent\",\n  \"RecordStop\": \"Record | Stop\",\n  \"Redo\": \"Redo\",\n  \"Refresh\": \"Refresh\",\n  \"Region\": \"Region\",\n  \"RegionSelector\": \"Region Selector\",\n  \"RemoveFromList\": \"Remove from List\",\n  \"Reset\": \"Reset\",\n  \"Resize\": \"Resize\",\n  \"RestoreDefaults\": \"Restore Defaults\",\n  \"Right\": \"Right\",\n  \"SaveToClipboard\": \"Save to Clipboard\",\n  \"Screen\": \"Screen\",\n  \"ScreenShot\": \"ScreenShot\",\n  \"ScreenShotActiveWindow\": \"ScreenShot Active Window\",\n  \"ScreenShotDesktop\": \"ScreenShot Desktop\",\n  \"ScreenShotSaved\": \"ScreenShot Saved\",\n  \"SelectFFmpegFolder\": \"Select FFmpeg Folder\",\n  \"SelectOutFolder\": \"Select Output Folder\",\n  \"SeparateAudioFiles\": \"Separate file for every audio source\",\n  \"ShowSysNotify\": \"Show System Tray Notifications\",\n  \"SnapToWindow\": \"Snap to Window\",\n  \"Sounds\": \"Sounds\",\n  \"StartStopRecording\": \"Start/Stop Recording\",\n  \"StreamingKeys\": \"Streaming Keys\",\n  \"Timeout\": \"Timeout\",\n  \"ToggleMouseClicks\": \"Toggle Mouse Clicks\",\n  \"ToggleKeystrokes\": \"Toggle Keystrokes\",\n  \"Tools\": \"Tools\",\n  \"Top\": \"Top\",\n  \"TrayIcon\": \"Tray Icon\",\n  \"Trim\": \"Trim\",\n  \"Undo\": \"Undo\",\n  \"UploadToImgur\": \"Upload to Imgur\",\n  \"UseProxyAuth\": \"Use Proxy Authentication\",\n  \"UserName\": \"User Name\",\n  \"VarFrameRate\": \"Variable Frame Rate\",\n  \"Video\": \"Video\",\n  \"VideoEncoder\": \"Video Encoder\",\n  \"VideoSaved\": \"Video Saved\",\n  \"VideoSource\": \"Video Source\",\n  \"ViewCrashLogs\": \"View Crash Logs\",\n  \"ViewLicenses\": \"View Licenses\",\n  \"ViewOnGitHub\": \"View on GitHub\",\n  \"WantToTranslate\": \"Want to Translate?\",\n  \"WebCam\": \"Webcam\",\n  \"WebCamSeparateFile\": \"Record Webcam to separate file\",\n  \"WebCamView\": \"WebCam View\",\n  \"Website\": \"Website\",\n  \"Window\": \"Window\",\n  \"WindowScreenShotTransparency\": \"ScreenShots in Window mode should be Transparent\",\n  \"Yes\": \"Yes\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/es.json",
    "content": "{\n  \"About\": \"Acerca de\",\n  \"AccentColor\": \"Color de tono\",\n  \"Add\": \"Añadir\",\n  \"AlwaysOnTop\": \"Siempre visible\",\n  \"Audio\": \"Audio\",\n  \"AudioFormat\": \"Formato de audio\",\n  \"AudioSaved\": \"Audio guardado\",\n  \"BackColor\": \"Color de fondo\",\n  \"BorderColor\": \"Color del borde\",\n  \"BorderThickness\": \"Tamaño del borde\",\n  \"Bottom\": \"Abajo\",\n  \"CaptureDuration\": \"Duración de captura (en seg.)\",\n  \"Center\": \"Centro\",\n  \"Changelog\": \"Registro de cambios\",\n  \"Clear\": \"Limpiar\",\n  \"ClearRecentList\": \"Limpiar lista reciente\",\n  \"Clipboard\": \"Portapapeles\",\n  \"Close\": \"Cerrar\",\n  \"Color\": \"Color\",\n  \"ConfigCodecs\": \"Configurar códecs\",\n  \"Configure\": \"Configuración\",\n  \"CopyOutPathClipboard\": \"Copiar ruta del archivo de destino al portapapeles\",\n  \"CopyPath\": \"Copiar ruta\",\n  \"CopyToClipboard\": \"Copiar al portapapeles\",\n  \"CornerRadius\": \"Radio del borde\",\n  \"CrashLogs\": \"Registros de congelamiento\",\n  \"Crop\": \"Cortar\",\n  \"CustomSize\": \"Tamaño personalizado\",\n  \"CustomUrl\": \"URL personalizado\",\n  \"DarkTheme\": \"Tema oscuro\",\n  \"Delete\": \"Eliminar\",\n  \"DiscardChanges\": \"Descartar cambios\",\n  \"Disk\": \"Unidad\",\n  \"Donate\": \"Donar\",\n  \"DownloadFFmpeg\": \"Descargar FFmpeg\",\n  \"Edit\": \"Editar\",\n  \"Elapsed\": \"Transcurrido\",\n  \"ErrorOccurred\": \"Ocurrió un error\",\n  \"Exit\": \"Salir\",\n  \"FFmpegFolder\": \"Carpeta de FFmpeg\",\n  \"FFmpegLog\": \"Registro de FFmpeg\",\n  \"FileMenu\": \"Archivo\",\n  \"FileMenuNew\": \"Nuevo\",\n  \"FileMenuOpen\": \"Abrir\",\n  \"FileMenuSave\": \"Guardar\",\n  \"FileNaming\": \"Nombre del archivo\",\n  \"FontSize\": \"Tamaño de fuente\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Pantalla completa\",\n  \"HideOnFullScreenShot\": \"Ocultar en captura a pantalla completa\",\n  \"Host\": \"Host\",\n  \"Hotkeys\": \"Atajos\",\n  \"ImageEditor\": \"Editor de imagen\",\n  \"ImgEmpty\": \"No guardado. La imagen está vacía\",\n  \"ImgFormat\": \"Formato de imagen\",\n  \"ImgSavedClipboard\": \"Imagen guardada en el portapapeles\",\n  \"ImageUploadFailed\": \"Error al subir la imagen\",\n  \"ImageUploadSuccess\": \"Imagen subida con éxito\",\n  \"ImageUploading\": \"Subiendo imagen\",\n  \"IncludeClicks\": \"Incluir clics del ratón\",\n  \"IncludeCursor\": \"Incluir el cursor\",\n  \"IncludeKeys\": \"Incluir pulsaciones de teclas\",\n  \"Keymap\": \"Mapeado de teclas\",\n  \"Keystrokes\": \"Pulsaciones de teclas\",\n  \"KeystrokesHistoryCount\": \"Recuento de historia\",\n  \"KeystrokesHistorySpacing\": \"Espaciado de historia\",\n  \"KeystrokesSeparateFile\": \"Guardar en archivo de texto separado\",\n  \"Language\": \"Idioma\",\n  \"Left\": \"Izquierda\",\n  \"LoopbackSource\": \"Fuente de salida de altavoz\",\n  \"MaxRecent\": \"Elementos máximos que conservar\",\n  \"MaxTextLength\": \"Tamaño máximo de texto\",\n  \"MicSource\": \"Fuente de salida del micrófono\",\n  \"Minimize\": \"Minimizar\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Minimizar al área de notificaciones\",\n  \"MinTrayStartup\": \"Minimizar al área de notificaciones al iniciar\",\n  \"MinTrayClose\": \"Minimizar al área de notificaciones al cerrar\",\n  \"MouseClicks\": \"Clics del ratón\",\n  \"MouseMiddleClickColor\": \"Color de clic medio\",\n  \"MousePointer\": \"Puntero del ratón\",\n  \"MouseRightClickColor\": \"Color del clic derecho\",\n  \"NewWindow\": \"Nueva ventana\",\n  \"No\": \"No\",\n  \"None\": \"Ninguno\",\n  \"Notifications\": \"Notificaciones\",\n  \"NotSaved\": \"No guardado\",\n  \"NoWebcam\": \"Sin cámara web\",\n  \"Ok\": \"Aceptar\",\n  \"OnlyAudio\": \"Solo audio\",\n  \"Opacity\": \"Opacidad\",\n  \"OpenFromClipboard\": \"Abrir desde el portapapeles\",\n  \"OpenOutFolder\": \"Abrir carpeta de destino\",\n  \"OutFolder\": \"Destino\",\n  \"Overlays\": \"Superposiciones\",\n  \"Padding\": \"Relleno\",\n  \"Password\": \"Contraseña\",\n  \"Paused\": \"Grabación pausada\",\n  \"PauseResume\": \"Pausar | Reanudar\",\n  \"PauseResumeRecording\": \"Pausar/Reanudar grabación\",\n  \"Port\": \"Puerto\",\n  \"Preview\": \"Vista Previa\",\n  \"PreStartCountdown\": \"Cuenta atrás previa al inicio (seg.)\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Calidad\",\n  \"Radius\": \"Radio\",\n  \"Recent\": \"Reciente\",\n  \"RecordStop\": \"Grabar | Detener\",\n  \"Redo\": \"Rehacer\",\n  \"Refresh\": \"Actualizar\",\n  \"Region\": \"Área\",\n  \"RegionSelector\": \"Selector de área\",\n  \"RemoveFromList\": \"Quitar de la lista\",\n  \"Reset\": \"Restablecer\",\n  \"Resize\": \"Tamaño\",\n  \"RestoreDefaults\": \"Valores por defecto\",\n  \"Right\": \"Derecha\",\n  \"SaveToClipboard\": \"Guardar en el portapapeles\",\n  \"Screen\": \"Pantalla\",\n  \"ScreenShot\": \"Captura de pantalla\",\n  \"ScreenShotActiveWindow\": \"Capturar ventana activa\",\n  \"ScreenShotDesktop\": \"Captura de pantalla del escritorio\",\n  \"ScreenShotSaved\": \"Captura de pantalla guardada\",\n  \"SelectFFmpegFolder\": \"Seleccionar carpeta de FFmpeg\",\n  \"SelectOutFolder\": \"Seleccionar carpeta de destino\",\n  \"SeparateAudioFiles\": \"Archivo separado para cada fuente de audio\",\n  \"ShowSysNotify\": \"Mostrar Mensajes en el área de notificaciones\",\n  \"SnapToWindow\": \"Ajustar a la ventana\",\n  \"Sounds\": \"Sonidos\",\n  \"StartStopRecording\": \"Iniciar/Detener grabación\",\n  \"StreamingKeys\": \"Claves de streaming\",\n  \"Timeout\": \"Tiempo terminado\",\n  \"ToggleMouseClicks\": \"Cambiar clics del ratón\",\n  \"ToggleKeystrokes\": \"Cambiar pulsaciones de teclas\",\n  \"Tools\": \"Herramientas\",\n  \"Top\": \"Arriba\",\n  \"TrayIcon\": \"Icono en el área de notificaciones\",\n  \"Trim\": \"Recortar\",\n  \"Undo\": \"Deshacer\",\n  \"UploadToImgur\": \"Subir a Imgur\",\n  \"UseProxyAuth\": \"Usar autenticación Proxy\",\n  \"UserName\": \"Usuario\",\n  \"VarFrameRate\": \"Fotogramas variables\",\n  \"Video\": \"Vídeo\",\n  \"VideoEncoder\": \"Codificador de vídeo\",\n  \"VideoSaved\": \"Vídeo guardado\",\n  \"VideoSource\": \"Fuente de vídeo\",\n  \"ViewCrashLogs\": \"Ver registros de cogelamiento\",\n  \"ViewLicenses\": \"Ver licencias\",\n  \"ViewOnGitHub\": \"Ver en GitHub\",\n  \"WantToTranslate\": \"¿Quieres traducir?\",\n  \"WebCam\": \"Cámara web\",\n  \"WebCamSeparateFile\": \"Grabar cámara web en archivo separado\",\n  \"WebCamView\": \"Vista de cámara web\",\n  \"Website\": \"Sitio web\",\n  \"Window\": \"Ventana\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Sí\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/fi.json",
    "content": "{\n  \"About\": \"Tietoja\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"Aina päällimmäisenä\",\n  \"Audio\": \"Ääni\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Ääni tallennettu\",\n  \"BackColor\": \"Taustaväri\",\n  \"BorderColor\": \"Reunaväri\",\n  \"BorderThickness\": \"Reunan paksuus\",\n  \"Bottom\": \"Alapuoli\",\n  \"CaptureDuration\": \"Tallennuksen kesto (sekunneissa)\",\n  \"Center\": \"Keski\",\n  \"Changelog\": \"Muutosloki\",\n  \"Clear\": \"Tyhjennä\",\n  \"ClearRecentList\": \"Tyhjennä viimeisimmät\",\n  \"Clipboard\": \"Leikepöytä\",\n  \"Close\": \"Sulje\",\n  \"Color\": \"Väri\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Määritä\",\n  \"CopyOutPathClipboard\": \"Kopioi tiedostopolku leikepöydälle\",\n  \"CopyPath\": \"Kopioi polku\",\n  \"CopyToClipboard\": \"Kopioi leikepöydälle\",\n  \"CornerRadius\": \"Kulman pyöreys\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Poista\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"Levy\",\n  \"Donate\": \"Lahjoita\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"Tapahtui virhe\",\n  \"Exit\": \"Poistu\",\n  \"FFmpegFolder\": \"FFmpeg Kansio\",\n  \"FFmpegLog\": \"FFmpeg Loki\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Fontin koko\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"Koko näyttö\",\n  \"HideOnFullScreenShot\": \"Piilota koko ruudun ruutukaappauksessa\",\n  \"Host\": \"Palvelin\",\n  \"Hotkeys\": \"Pikanäppäimet\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Otettu kuva oli tyhjä ja sitä ei tallennettu\",\n  \"ImgFormat\": \"Kuvan formaatti\",\n  \"ImgSavedClipboard\": \"Kuva tallennettu leikepöydälle\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Näytä hiiren painallukset\",\n  \"IncludeCursor\": \"Näytä kursori\",\n  \"IncludeKeys\": \"Näytä näppäimistön painallukset\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"Näppäimistön painallukset\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Kieli\",\n  \"Left\": \"Vasen\",\n  \"LoopbackSource\": \"Kaiuttimen ulostulo\",\n  \"MaxRecent\": \"Viimeisimmät listan maksimimäärä\",\n  \"MaxTextLength\": \"Tekstin maksimipituus\",\n  \"MicSource\": \"Mikrofonin tulo\",\n  \"Minimize\": \"Pienennä\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Pienennä tehtäväpalkkiin\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"Hiiren painallukset\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Ei\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"Ei tallennettu\",\n  \"NoWebcam\": \"Ei webkameraa\",\n  \"Ok\": \"\",\n  \"OnlyAudio\": \"Vain ääni\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"Avaa tallennuskansio\",\n  \"OutFolder\": \"Tallennuskansio\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Salasana\",\n  \"Paused\": \"Tallennus keskeytetty\",\n  \"PauseResume\": \"Keskeytä | Jatka\",\n  \"PauseResumeRecording\": \"Keskeytä/Jatka tallennusta\",\n  \"Port\": \"Portti\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"Välityspalvelin\",\n  \"Quality\": \"Laatu\",\n  \"Radius\": \"Säde\",\n  \"Recent\": \"Viimeisimmät\",\n  \"RecordStop\": \"Nauhoita | Lopeta\",\n  \"Redo\": \"\",\n  \"Refresh\": \"Päivitä\",\n  \"Region\": \"Alue\",\n  \"RegionSelector\": \"Aluevalitsin\",\n  \"RemoveFromList\": \"Poista listasta\",\n  \"Reset\": \"Nollaa\",\n  \"Resize\": \"\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Oikea\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Näyttö\",\n  \"ScreenShot\": \"Ruutukaappaus\",\n  \"ScreenShotActiveWindow\": \"Ota ruutukaappaus aktiivisesta ikkunasta\",\n  \"ScreenShotDesktop\": \"Ota ruutukaappaus työpöydästä\",\n  \"ScreenShotSaved\": \"Ruutukaappaus tallennettu\",\n  \"SelectFFmpegFolder\": \"Valitse FFmpeg kansio\",\n  \"SelectOutFolder\": \"Valitse tallennuskansio\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Näytä tehtäväpalkin ilmoitukset\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Aloita/Lopeta tallennus\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"Aikakatkaisu\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"Ylä\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Käytä välityspalvelimessa tunnistautumista\",\n  \"UserName\": \"Käyttäjänimi\",\n  \"VarFrameRate\": \"Muuttuva ruudunpäivitysnopeus\",\n  \"Video\": \"\",\n  \"VideoEncoder\": \"Video encoder\",\n  \"VideoSaved\": \"Video tallennettu\",\n  \"VideoSource\": \"Videolähde\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Haluatko kääntäjäksi?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"Webkameran näkymä\",\n  \"Website\": \"\",\n  \"Window\": \"Ikkuna\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Kyllä\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/fr.json",
    "content": "{\n  \"About\": \"À propos\",\n  \"AccentColor\": \"Couleur d'accentuation \",\n  \"Add\": \"Ajouter\",\n  \"AlwaysOnTop\": \"Toujours afficher au-dessus\",\n  \"Audio\": \"Audio\",\n  \"AudioFormat\": \"Format audio\",\n  \"AudioSaved\": \"Audio enregistré\",\n  \"BackColor\": \"Couleur d'arrière-plan \",\n  \"BorderColor\": \"Couleur de bordure\",\n  \"BorderThickness\": \"Épaisseur de bordure\",\n  \"Bottom\": \"Bas\",\n  \"CaptureDuration\": \"Durée de l'enregistrement (s) \",\n  \"Center\": \"Centré\",\n  \"Changelog\": \"Journal des modifications\",\n  \"Clear\": \"Effacer\",\n  \"ClearRecentList\": \"Effacer la liste des captures récentes\",\n  \"Clipboard\": \"Presse-papier\",\n  \"Close\": \"Fermer\",\n  \"Color\": \"Couleur \",\n  \"ConfigCodecs\": \"Configurer les codecs\",\n  \"Configure\": \"Configurer\",\n  \"CopyOutPathClipboard\": \"Copier le chemin du fichier de sortie dans le presse-papier\",\n  \"CopyPath\": \"Copier le chemin\",\n  \"CopyToClipboard\": \"Copier dans le presse-papier\",\n  \"CornerRadius\": \"Rayon des coins \",\n  \"CrashLogs\": \"Journaux d'erreurs\",\n  \"Crop\": \"Rogner\",\n  \"CustomSize\": \"Taille personnalisée\",\n  \"CustomUrl\": \"URL personnalisée \",\n  \"DarkTheme\": \"Thème sombre\",\n  \"Delete\": \"Supprimer\",\n  \"DiscardChanges\": \"Annuler tout\",\n  \"Disk\": \"Disque dur\",\n  \"Donate\": \"Faire un don\",\n  \"DownloadFFmpeg\": \"Télécharger FFmpeg\",\n  \"Edit\": \"Modifier\",\n  \"Elapsed\": \"Temps écoulé\",\n  \"ErrorOccurred\": \"Une erreur s'est produite\",\n  \"Exit\": \"Quitter\",\n  \"FFmpegFolder\": \"Dossier FFmpeg\",\n  \"FFmpegLog\": \"Journaux FFmpeg\",\n  \"FileMenu\": \"Fichier\",\n  \"FileMenuNew\": \"Nouveau\",\n  \"FileMenuOpen\": \"Ouvrir\",\n  \"FileMenuSave\": \"Enregistrer\",\n  \"FileNaming\": \"Noms des fichiers\",\n  \"FontSize\": \"Taille de la police\",\n  \"FrameRate\": \"i/s \",\n  \"FullScreen\": \"Tous les écrans\",\n  \"HideOnFullScreenShot\": \"Cacher lors d'une capture de tous les écrans\",\n  \"Host\": \"Hôte \",\n  \"Hotkeys\": \"Raccourcis\",\n  \"ImageEditor\": \"Éditeur d'Image\",\n  \"ImgEmpty\": \"Non enregistré. L'image capturée était vide.\",\n  \"ImgFormat\": \"Format d'image \",\n  \"ImgSavedClipboard\": \"Image enregistrée dans le presse-papier\",\n  \"ImageUploadFailed\": \"L'upload vers Imgur a échoué\",\n  \"ImageUploadSuccess\": \"L'upload vers Imgur a réussi\",\n  \"ImageUploading\": \"Upload vers Imgur en cours\",\n  \"IncludeClicks\": \"Enregistrer les clics de souris\",\n  \"IncludeCursor\": \"Enregistrer le pointeur\",\n  \"IncludeKeys\": \"Enregistrer les frappes au clavier\",\n  \"Keymap\": \"Disposition du clavier \",\n  \"Keystrokes\": \"Frappes clavier\",\n  \"KeystrokesHistoryCount\": \"Dernières frappes affichées \",\n  \"KeystrokesHistorySpacing\": \"Espacement \",\n  \"KeystrokesSeparateFile\": \"Enregistrer dans un fichier séparé\",\n  \"Language\": \"Langue \",\n  \"Left\": \"Gauche\",\n  \"LoopbackSource\": \"Source de sortie audio\",\n  \"MaxRecent\": \"Nombre maximum d'éléments à conserver \",\n  \"MaxTextLength\": \"Longueur maximum du texte \",\n  \"MicSource\": \"Source d'entrée audio\",\n  \"Minimize\": \"Minimiser\",\n  \"MinToTrayOnCaptureStart\": \"Minimiser au démarrage de l'enregistrement\",\n  \"MinTray\": \"Minimiser dans la zone de notification\",\n  \"MinTrayStartup\": \"Minimiser au démarrage\",\n  \"MinTrayClose\": \"Minimiser à la fermeture\",\n  \"MouseClicks\": \"Clics\",\n  \"MouseMiddleClickColor\": \"Couleur du clic milieu \",\n  \"MousePointer\": \"Pointeur\",\n  \"MouseRightClickColor\": \"Couleur du clic droit \",\n  \"NewWindow\": \"Nouvelle fenêtre\",\n  \"No\": \"Non\",\n  \"None\": \"Aucun\",\n  \"Notifications\": \"Notifications \",\n  \"NotSaved\": \"Non enregistré\",\n  \"NoWebcam\": \"Pas de webcam\",\n  \"Ok\": \"Ok\",\n  \"OnlyAudio\": \"Audio uniquement\",\n  \"Opacity\": \"Opacité \",\n  \"OpenFromClipboard\": \"Importer depuis le presse-papier\",\n  \"OpenOutFolder\": \"Ouvrir le dossier de sortie\",\n  \"OutFolder\": \"Dossier de sortie\",\n  \"Overlays\": \"Masque de vidéo\",\n  \"Padding\": \"Marge intérieure\",\n  \"Password\": \"Mot de passe \",\n  \"Paused\": \"Enregistrement mis en pause\",\n  \"PauseResume\": \"Mettre en pause | Reprendre\",\n  \"PauseResumeRecording\": \"Mettre en pause/reprendre\",\n  \"Port\": \"Port \",\n  \"Preview\": \"Aperçu\",\n  \"PreStartCountdown\": \"Délai avant démarrage (s) \",\n  \"Proxy\": \"Serveur proxy\",\n  \"Quality\": \"Qualité  \",\n  \"Radius\": \"Rayon \",\n  \"Recent\": \"Captures récentes\",\n  \"RecordStop\": \"Enregistrer | Arrêter\",\n  \"Redo\": \"Rétablir\",\n  \"Refresh\": \"Actualiser\",\n  \"Region\": \"Zone\",\n  \"RegionSelector\": \"sélecteur de zone\",\n  \"RemoveFromList\": \"Supprimer de la liste\",\n  \"Reset\": \"Réinitialiser\",\n  \"Resize\": \"Redimensionner\",\n  \"RestoreDefaults\": \"Restaurer les paramètres\",\n  \"Right\": \"Droite\",\n  \"SaveToClipboard\": \"Copier dans le presse-papier\",\n  \"Screen\": \"Écran\",\n  \"ScreenShot\": \"Capture d'écran\",\n  \"ScreenShotActiveWindow\": \"Capture d'écran (fenêtre active)\",\n  \"ScreenShotDesktop\": \"Capture d'écran (tous les écrans)\",\n  \"ScreenShotSaved\": \"Capture d'écran enregistrée\",\n  \"SelectFFmpegFolder\": \"Sélectionner le dossier FFmpeg\",\n  \"SelectOutFolder\": \"Sélectionner le dossier de sortie\",\n  \"SeparateAudioFiles\": \"Créer un fichier pour chaque source audio\",\n  \"ShowSysNotify\": \"Afficher les notifications\",\n  \"SnapToWindow\": \"Ajuster à la taille de la fenêtre\",\n  \"Sounds\": \"Sons\",\n  \"StartStopRecording\": \"Démarrer/arrêter\",\n  \"StreamingKeys\": \"Clés de streaming\",\n  \"Timeout\": \"Durée d'affichage maximum \",\n  \"ToggleMouseClicks\": \"Clics de souris : on/off\",\n  \"ToggleKeystrokes\": \"Frappes au clavier : on/off\",\n  \"Tools\": \"Outils\",\n  \"Top\": \"Haut\",\n  \"TrayIcon\": \"Zone de notification\",\n  \"Trim\": \"Découper\",\n  \"Undo\": \"Annuler\",\n  \"UploadToImgur\": \"Uploader vers Imgur\",\n  \"UseProxyAuth\": \"Utiliser une authentification proxy\",\n  \"UserName\": \"Nom d'utilisateur \",\n  \"VarFrameRate\": \"Fréquence d'images variable\",\n  \"Video\": \"Vidéo\",\n  \"VideoEncoder\": \"Encodeur vidéo\",\n  \"VideoSaved\": \"Vidéo enregistrée\",\n  \"VideoSource\": \"Source vidéo\",\n  \"ViewCrashLogs\": \"Afficher les journaux d'erreurs\",\n  \"ViewLicenses\": \"Afficher les licences\",\n  \"ViewOnGitHub\": \"Afficher sur GitHub\",\n  \"WantToTranslate\": \"Vous voulez aider à traduire ?\",\n  \"WebCam\": \"Webcam\",\n  \"WebCamSeparateFile\": \"Enregistrer la webcam dans un fichier séparé\",\n  \"WebCamView\": \"Aperçu de la webcam\",\n  \"Website\": \"Site web\",\n  \"Window\": \"Fenêtre\",\n  \"WindowScreenShotTransparency\": \"Les captures d'écran en mode fenêtre doivent être transparentes\",\n  \"Yes\": \"Oui\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/he.json",
    "content": "{\n  \"About\": \"אודות\",\n  \"AccentColor\": \"צבע הדגשה\",\n  \"Add\": \"הוסף\",\n  \"AlwaysOnTop\": \"תמיד בקדמת המסך\",\n  \"Audio\": \"קול\",\n  \"AudioFormat\": \"פורמט קול\",\n  \"AudioSaved\": \"ההקלטה נשמרה\",\n  \"BackColor\": \"צבע הרקע\",\n  \"BorderColor\": \"צבע גבולות\",\n  \"BorderThickness\": \"עובי גבולות\",\n  \"Bottom\": \"תחתון\",\n  \"CaptureDuration\": \"משך ההקלטה (בשניות)\",\n  \"Center\": \"מרכז\",\n  \"Changelog\": \"מסמך שינויים\",\n  \"Clear\": \"נקה\",\n  \"ClearRecentList\": \"נקה את הרשימה\",\n  \"Clipboard\": \"לוח העתקה\",\n  \"Close\": \"סגירה\",\n  \"Color\": \"צבע\",\n  \"ConfigCodecs\": \"הגדרות הקודאק\",\n  \"Configure\": \"הגדרות\",\n  \"CopyOutPathClipboard\": \"העתיק את מיקום הסרטון ללוח\",\n  \"CopyPath\": \"העתק נתיב\",\n  \"CopyToClipboard\": \"העתק ללוח\",\n  \"CornerRadius\": \"רדיוס קצה\",\n  \"CrashLogs\": \"לוגי קריסה\",\n  \"Crop\": \"חתוך\",\n  \"CustomSize\": \"גודל מותאם אישית\",\n  \"CustomUrl\": \"קישור מותאם אישית\",\n  \"DarkTheme\": \"עיצוב כהה\",\n  \"Delete\": \"מחיקה\",\n  \"DiscardChanges\": \"ביטול שינויים\",\n  \"Disk\": \"דיסק\",\n  \"Donate\": \"תרום\",\n  \"DownloadFFmpeg\": \"הורדת את FFmpeg\",\n  \"Edit\": \"ערוך\",\n  \"Elapsed\": \"עבור\",\n  \"ErrorOccurred\": \"אירעה שגיאה\",\n  \"Exit\": \"יציאה\",\n  \"FFmpegFolder\": \"תיקיית FFmpeg\",\n  \"FFmpegLog\": \"יומן FFmpeg\",\n  \"FileMenu\": \"קובץ\",\n  \"FileMenuNew\": \"חדש\",\n  \"FileMenuOpen\": \"פתח\",\n  \"FileMenuSave\": \"שמור\",\n  \"FileNaming\": \"שם הקובץ\",\n  \"FontSize\": \"גודל גופן\",\n  \"FrameRate\": \"קצב פריימים\",\n  \"FullScreen\": \"מסך מלא\",\n  \"HideOnFullScreenShot\": \"העלם בצילום מסך מלא\",\n  \"Host\": \"מארח\",\n  \"Hotkeys\": \"מקשי קיצור\",\n  \"ImageEditor\": \"עורך התמונה\",\n  \"ImgEmpty\": \"לא נשמר. התמונה ריקה.\",\n  \"ImgFormat\": \"פורמט תמונה\",\n  \"ImgSavedClipboard\": \"התמונה נשמרה ללוח\",\n  \"ImageUploadFailed\": \"העלאת התמונה נכשלה\",\n  \"ImageUploadSuccess\": \"העלאת התמונה הצליחה\",\n  \"ImageUploading\": \"התמונה בהעלאה\",\n  \"IncludeClicks\": \"הצג לחיצות עכבר\",\n  \"IncludeCursor\": \"הצג עכבר\",\n  \"IncludeKeys\": \"הצג הקשות\",\n  \"Keymap\": \"מפת המקשים\",\n  \"Keystrokes\": \"הקשות\",\n  \"KeystrokesHistoryCount\": \"ספירת מספר ההקשות על אותו מקש\",\n  \"KeystrokesHistorySpacing\": \"היסטורית הקשות על רווח\",\n  \"KeystrokesSeparateFile\": \"שמור את ההקשות בקובץ נפרד\",\n  \"Language\": \"שפה\",\n  \"Left\": \"שמאל\",\n  \"LoopbackSource\": \"מקור קלט רמקול\",\n  \"MaxRecent\": \"מקסימום קבצים ברשימה\",\n  \"MaxTextLength\": \"אורך טקסט מקסימלי\",\n  \"MicSource\": \"מקור קלט מיקרופון\",\n  \"Minimize\": \"צמצום\",\n  \"MinToTrayOnCaptureStart\": \"צמצם את התוכנה בהפעלתה\",\n  \"MinTray\": \"צמצם את התוכנה אל שורת הפעולה\",\n  \"MinTrayStartup\": \"צמצם את התוכנה לתפריט האייקונים\",\n  \"MinTrayClose\": \"צמצם את התוכנה\",\n  \"MouseClicks\": \"הקשות עכבר\",\n  \"MouseMiddleClickColor\": \"צבע הלחיצה על המקש האמצעי בעכבר\",\n  \"MousePointer\": \"מצביע העכבר\",\n  \"MouseRightClickColor\": \"צבע הלחיצה על המקש הימני בעכבר\",\n  \"NewWindow\": \"חלון חדש\",\n  \"No\": \"לא\",\n  \"None\": \"כלום\",\n  \"Notifications\": \"התראות\",\n  \"NotSaved\": \"לא נשמר.\",\n  \"NoWebcam\": \"אין מצלמת רשת\",\n  \"Ok\": \"קבל\",\n  \"OnlyAudio\": \"קול בלבד\",\n  \"Opacity\": \"אטימות\",\n  \"OpenFromClipboard\": \"פתח מלוח ההעתקה\",\n  \"OpenOutFolder\": \"פתח תיקיית יעד\",\n  \"OutFolder\": \"תיקיית יעד\",\n  \"Overlays\": \"שכבות\",\n  \"Padding\": \"ריפוד\",\n  \"Password\": \"סיסמה\",\n  \"Paused\": \"ההקלטה בהשהיה\",\n  \"PauseResume\": \"עצור | המשך\",\n  \"PauseResumeRecording\": \"עצור/המשך הקלטה\",\n  \"Port\": \"פורט\",\n  \"Preview\": \"תצוגה מקדימה\",\n  \"PreStartCountdown\": \"ספירה לאחור לפני ההתחלה\",\n  \"Proxy\": \"פרוקסי\",\n  \"Quality\": \"איכות\",\n  \"Radius\": \"רדיוס\",\n  \"Recent\": \"לאחרונה\",\n  \"RecordStop\": \"הקלט | עצור\",\n  \"Redo\": \"מוכן\",\n  \"Refresh\": \"רענן\",\n  \"Region\": \"איזור\",\n  \"RegionSelector\": \"סמן לבחירת איזור\",\n  \"RemoveFromList\": \"מחק מהרשימה\",\n  \"Reset\": \"איפוס\",\n  \"Resize\": \"שנה גודל\",\n  \"RestoreDefaults\": \"שחזר לברירת מחדל\",\n  \"Right\": \"ימין\",\n  \"SaveToClipboard\": \"שמור ללוח ההעתקה\",\n  \"Screen\": \"מסך\",\n  \"ScreenShot\": \"צילום מסך\",\n  \"ScreenShotActiveWindow\": \"צלם את החלון הפעיל\",\n  \"ScreenShotDesktop\": \"צלם את שולחן העבודה\",\n  \"ScreenShotSaved\": \"צילום המסך נשמר\",\n  \"SelectFFmpegFolder\": \"בחר תיקיית FFmpeg\",\n  \"SelectOutFolder\": \"בחר תיקיית יעד\",\n  \"SeparateAudioFiles\": \"קובץ קול נפרד\",\n  \"ShowSysNotify\": \"הצג התראות מערכת\",\n  \"SnapToWindow\": \"הצמד לחלון\",\n  \"Sounds\": \"שמע\",\n  \"StartStopRecording\": \"התחל/עצור הקלטה\",\n  \"StreamingKeys\": \"מקשי סטרימינג\",\n  \"Timeout\": \"ספירה לאחור\",\n  \"ToggleMouseClicks\": \"החלף הקשות עכבר\",\n  \"ToggleKeystrokes\": \"החלף הקשות\",\n  \"Tools\": \"כלים\",\n  \"Top\": \"עליון\",\n  \"TrayIcon\": \"אייקון\",\n  \"Trim\": \"חתוך\",\n  \"Undo\": \"ביטול\",\n  \"UploadToImgur\": \"העלה אל Imgur\",\n  \"UseProxyAuth\": \"השתמש ב-proxy כדי להתחבר\",\n  \"UserName\": \"שם משתמש\",\n  \"VarFrameRate\": \"משתנה מהירות פריימים\",\n  \"Video\": \"וידאו\",\n  \"VideoEncoder\": \"מקודד וידאו\",\n  \"VideoSaved\": \"הוידאו נשמר\",\n  \"VideoSource\": \"מקור וידאו\",\n  \"ViewCrashLogs\": \"צפה בלוגי הקריסה\",\n  \"ViewLicenses\": \"צפה ברשיונות\",\n  \"ViewOnGitHub\": \"צפה ב-GitHub\",\n  \"WantToTranslate\": \"האם תרצה לתרגם?\",\n  \"WebCam\": \"מצלמת רשת\",\n  \"WebCamSeparateFile\": \"קובץ נפרד למצלמת רשת\",\n  \"WebCamView\": \"הצג מצלמת רשת\",\n  \"Website\": \"אתר\",\n  \"Window\": \"חלון\",\n  \"WindowScreenShotTransparency\": \"צילומי מסך במצב ווינדוס צריכים להיות שקופים\",\n  \"Yes\": \"כן\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/hi.json",
    "content": "{\n  \"About\": \"जानकारी\",\n  \"AccentColor\": \"\",\n  \"Add\": \"जोड़ें\",\n  \"AlwaysOnTop\": \"हमेशा ऊपर रहे\",\n  \"Audio\": \"ध्वनि\",\n  \"AudioFormat\": \"ऑडियो प्रारूप\",\n  \"AudioSaved\": \"ऑडियो सहेजा गया\",\n  \"BackColor\": \"\",\n  \"BorderColor\": \"बोर्डर रंग\",\n  \"BorderThickness\": \"\",\n  \"Bottom\": \"नीचे\",\n  \"CaptureDuration\": \"\",\n  \"Center\": \"मध्य\",\n  \"Changelog\": \"परिवर्तन लॉग\",\n  \"Clear\": \"रद्द करें\",\n  \"ClearRecentList\": \"सूची रद्द करें\",\n  \"Clipboard\": \"क्लिपबोर्ड\",\n  \"Close\": \"बंद करें\",\n  \"Color\": \"रंग\",\n  \"ConfigCodecs\": \"कोडेक कॉंफ़िगर करें\",\n  \"Configure\": \"स्वानुसार करें\",\n  \"CopyOutPathClipboard\": \"\",\n  \"CopyPath\": \"\",\n  \"CopyToClipboard\": \"क्‍लिपबोर्ड में कॉपी करें\",\n  \"CornerRadius\": \"\",\n  \"CrashLogs\": \"क्रैश लॉग्स\",\n  \"Crop\": \"काट-छांट करें\",\n  \"CustomSize\": \"कस्टम आकार\",\n  \"CustomUrl\": \"कस्टम Url\",\n  \"DarkTheme\": \"डार्क थीम\",\n  \"Delete\": \"मिटाए\",\n  \"DiscardChanges\": \"परिवर्तन छोड़ें\",\n  \"Disk\": \"डिस्क\",\n  \"Donate\": \"दान करें\",\n  \"DownloadFFmpeg\": \"डाउनलोड FFmpeg\",\n  \"Edit\": \"संपादित करें\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"कोई त्रुटि आई\",\n  \"Exit\": \"निकास\",\n  \"FFmpegFolder\": \"FFmpeg फ़ोल्डर\",\n  \"FFmpegLog\": \"\",\n  \"FileMenu\": \"फ़ाइल\",\n  \"FileMenuNew\": \"नया\",\n  \"FileMenuOpen\": \"खोलें\",\n  \"FileMenuSave\": \"सहेजें\",\n  \"FileNaming\": \"फ़ाइल नामकरण\",\n  \"FontSize\": \"फ़ॉंट आकार\",\n  \"FrameRate\": \"एफपीएस\",\n  \"FullScreen\": \"फ़ुलस्‍क्रीन\",\n  \"HideOnFullScreenShot\": \"पूर्ण स्क्रीन स्क्रीनशॉट पर छुपाएं\",\n  \"Host\": \"होस्ट\",\n  \"Hotkeys\": \"Hotkeys\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"नहीं सहेजा गया । ली गई छवि खाली थी\",\n  \"ImgFormat\": \"छवि स्वरूप (फॉर्मेट)\",\n  \"ImgSavedClipboard\": \"\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"माउस क्लिक शामिल करें\",\n  \"IncludeCursor\": \"कर्सर शामिल करें\",\n  \"IncludeKeys\": \"कीस्ट्रोक्स शामिल करें\",\n  \"Keymap\": \"कीमैप\",\n  \"Keystrokes\": \"कीस्ट्रोक्स\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"भाषा \",\n  \"Left\": \"बाएँ\",\n  \"LoopbackSource\": \"\",\n  \"MaxRecent\": \"\",\n  \"MaxTextLength\": \"\",\n  \"MicSource\": \"माइक्रोफोन स्रोत\",\n  \"Minimize\": \"छोटा करें\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"माउस क्लिक\",\n  \"MouseMiddleClickColor\": \"मध्य क्लिक रंग\",\n  \"MousePointer\": \"माउस सूचक\",\n  \"MouseRightClickColor\": \"दायां क्लिक रंग\",\n  \"NewWindow\": \"\",\n  \"No\": \"नहीं\",\n  \"None\": \"कोई नहीं\",\n  \"Notifications\": \"सूचनाएँ\",\n  \"NotSaved\": \"सहेजा नहीं\",\n  \"NoWebcam\": \"\",\n  \"Ok\": \"ठीक\",\n  \"OnlyAudio\": \"केवल ऑडियो\",\n  \"Opacity\": \"अस्पष्टता\",\n  \"OpenFromClipboard\": \"क्लिपबोर्ड से खोलें\",\n  \"OpenOutFolder\": \"आउटपुट फ़ोल्डर खोलें\",\n  \"OutFolder\": \"आउटपुट फ़ोल्डर\",\n  \"Overlays\": \"ओवरले\",\n  \"Padding\": \"\",\n  \"Password\": \"पासवर्ड\",\n  \"Paused\": \"\",\n  \"PauseResume\": \"\",\n  \"PauseResumeRecording\": \"\",\n  \"Port\": \"पोर्ट\",\n  \"Preview\": \"पूर्वावलोकन\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"प्रॉक्सी\",\n  \"Quality\": \"गुणवत्ता\",\n  \"Radius\": \"त्रिज्या\",\n  \"Recent\": \"हाल ही के\",\n  \"RecordStop\": \"\",\n  \"Redo\": \"फिर करें\",\n  \"Refresh\": \"रीफ्रेश करें\",\n  \"Region\": \"क्षेत्र\",\n  \"RegionSelector\": \"\",\n  \"RemoveFromList\": \"लिस्ट से निकाले\",\n  \"Reset\": \"रीसेट करें\",\n  \"Resize\": \"आकार बदलें\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"दाएँ\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"स्क्रीन\",\n  \"ScreenShot\": \"स्क्रीनशॉट\",\n  \"ScreenShotActiveWindow\": \"\",\n  \"ScreenShotDesktop\": \"\",\n  \"ScreenShotSaved\": \"स्क्रीनशॉट सहेजा गया\",\n  \"SelectFFmpegFolder\": \"FFmpeg फ़ोल्डर का चयन करें\",\n  \"SelectOutFolder\": \"आउटपुट फ़ोल्डर का चयन करें\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"सिस्टम ट्रे सूचनाएं दिखाएं\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"ध्वनियाँ\",\n  \"StartStopRecording\": \"\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"टाइमआउट\",\n  \"ToggleMouseClicks\": \"माउस क्लिक टॉगल करें\",\n  \"ToggleKeystrokes\": \"कीस्ट्रोक्स टॉगल करें\",\n  \"Tools\": \"\",\n  \"Top\": \"शीर्ष\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"प्रॉक्सी प्रमाणीकरण का उपयोग करें\",\n  \"UserName\": \"\",\n  \"VarFrameRate\": \"\",\n  \"Video\": \"वीडियो\",\n  \"VideoEncoder\": \"वीडियो एनकोडर\",\n  \"VideoSaved\": \"वीडियो सहेजा गया\",\n  \"VideoSource\": \"\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"लायसेंस देखें\",\n  \"ViewOnGitHub\": \"गिटहब पर कोड को देखें\",\n  \"WantToTranslate\": \"अनुवाद करना चाहते हैं?\",\n  \"WebCam\": \"वेबकैम\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"\",\n  \"Website\": \"वेबसाइट\",\n  \"Window\": \"विंडो\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"हाँ\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/id.json",
    "content": "{\n  \"About\": \"Tentang\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"Selalu di atas\",\n  \"Audio\": \"Suara\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Suara disimpan\",\n  \"BackColor\": \"Warna Dasar\",\n  \"BorderColor\": \"Warna Pembatas\",\n  \"BorderThickness\": \"Ketebalan Pembatas\",\n  \"Bottom\": \"Bawah\",\n  \"CaptureDuration\": \"Durasi tangkap (dalam detik)\",\n  \"Center\": \"Tengah\",\n  \"Changelog\": \"Catatan perubahan\",\n  \"Clear\": \"Bersihkan\",\n  \"ClearRecentList\": \"Bersihkan Daftar Baru-baru ini\",\n  \"Clipboard\": \"Papan klip\",\n  \"Close\": \"Tutup\",\n  \"Color\": \"Warna\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Atur\",\n  \"CopyOutPathClipboard\": \"Salin jalur hasil file ke Papan klip\",\n  \"CopyPath\": \"Jalur salin\",\n  \"CopyToClipboard\": \"Salin ke papan klip\",\n  \"CornerRadius\": \"Jarak pojok\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Hapus\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"Cakram\",\n  \"Donate\": \"Donasi\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"Sebuah Eror terjadi\",\n  \"Exit\": \"Keluar\",\n  \"FFmpegFolder\": \"Folder FFmpeg\",\n  \"FFmpegLog\": \"Catatan FFmpeg\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Ukuran font\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"Layar Penuh\",\n  \"HideOnFullScreenShot\": \"Sembunyikan pada Layar penuh Tangkapan layar\",\n  \"Host\": \"Penyedia\",\n  \"Hotkeys\": \"\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Tidak disimpan. Gambar yang diambil kosong\",\n  \"ImgFormat\": \"Format Gambar\",\n  \"ImgSavedClipboard\": \"Gambar disimpan ke Papan klip\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Memasukkan Klik Mouse\",\n  \"IncludeCursor\": \"Memasukkan Kursor\",\n  \"IncludeKeys\": \"Memasukkan Ketukan Kunci\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"Ketukan kunci\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Bahasa\",\n  \"Left\": \"Kiri\",\n  \"LoopbackSource\": \"Sumber Speaker Keluar\",\n  \"MaxRecent\": \"Maksimum barang yang tertahan\",\n  \"MaxTextLength\": \"Maksimum panjang teks\",\n  \"MicSource\": \"Sumber Microphone\",\n  \"Minimize\": \"Kecilkan\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Kecilkan ke Sistem Tray\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"Klik-an Mouse\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Tidak\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"Tidak disimpan\",\n  \"NoWebcam\": \"TanpaWebcam\",\n  \"Ok\": \"Ok\",\n  \"OnlyAudio\": \"Hanya Suara\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"Folder Keluar Terbuka\",\n  \"OutFolder\": \"Folder Keluar\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Kata Sandi\",\n  \"Paused\": \"Rekaman dijeda\",\n  \"PauseResume\": \"Jeda | Lanjutkan\",\n  \"PauseResumeRecording\": \"Jeda/Lanjutkan Rekaman\",\n  \"Port\": \"\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"\",\n  \"Quality\": \"Kualitas\",\n  \"Radius\": \"Jarak\",\n  \"Recent\": \"Baru-baru ini\",\n  \"RecordStop\": \"Rekam | Berhenti\",\n  \"Redo\": \"\",\n  \"Refresh\": \"Segarkan\",\n  \"Region\": \"Daerah\",\n  \"RegionSelector\": \"Pemilih daerah\",\n  \"RemoveFromList\": \"Singkirkan dari daftar\",\n  \"Reset\": \"Memasang Ulang\",\n  \"Resize\": \"Mengukur ulang\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Kanan\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Layar\",\n  \"ScreenShot\": \"Tangkap Layar\",\n  \"ScreenShotActiveWindow\": \"Tangkap layar Jendela Aktif\",\n  \"ScreenShotDesktop\": \"Tangkap layar Desktop\",\n  \"ScreenShotSaved\": \"Tangkapan layar disimpan\",\n  \"SelectFFmpegFolder\": \"Pilih Folder FFmpeg \",\n  \"SelectOutFolder\": \"Pilih Folder Keluar\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Tunjukan notifikasi Sistem Tray\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Mulai/Berhenti Rekaman\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"Waktu berakhir\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"Atas\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Gunakan autentikasi proxy\",\n  \"UserName\": \"Nama Pengguna\",\n  \"VarFrameRate\": \"Nilai Variabel Bingkai\",\n  \"Video\": \"\",\n  \"VideoEncoder\": \"Penyandi Video\",\n  \"VideoSaved\": \"Video disimpan\",\n  \"VideoSource\": \"Sumber Video\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Ingin menerjemahkan?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"Tampak Webcam\",\n  \"Website\": \"\",\n  \"Window\": \"Jendela\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Ya\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/is.json",
    "content": "{\n  \"About\": \"Um\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"Alltaf efst uppi\",\n  \"Audio\": \"Hljóð\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Hljóð vistað\",\n  \"BackColor\": \"Baklitur\",\n  \"BorderColor\": \"Jaðarlitur\",\n  \"BorderThickness\": \"Jaðarþykkt\",\n  \"Bottom\": \"Botn\",\n  \"CaptureDuration\": \"Tökulengd (í sekúndum)\",\n  \"Center\": \"Mið\",\n  \"Changelog\": \"Breytingarbók\",\n  \"Clear\": \"Hreinsa\",\n  \"ClearRecentList\": \"Hreinsa nýlega listann\",\n  \"Clipboard\": \"Klemmuspjald\",\n  \"Close\": \"Loka\",\n  \"Color\": \"Litur\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Stilla\",\n  \"CopyOutPathClipboard\": \"Afrita frálagsskráarleið til klemmuspjalds\",\n  \"CopyPath\": \"Afritunarleið\",\n  \"CopyToClipboard\": \"Afrita á klemmuspjald\",\n  \"CornerRadius\": \"Hornradíus\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Eyða\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"Diskur\",\n  \"Donate\": \"Gefa\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"Villa kom upp\",\n  \"Exit\": \"Hætta\",\n  \"FFmpegFolder\": \"FFmpeg mappa\",\n  \"FFmpegLog\": \"FFmpeg dagbók\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Leturgerðsstærð\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"Heilskjár\",\n  \"HideOnFullScreenShot\": \"Fela við heilskjásskjáskot\",\n  \"Host\": \"Hýsitölva\",\n  \"Hotkeys\": \"Flýtitakkar\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Ekki vistað. Tóm mynd var tekin.\",\n  \"ImgFormat\": \"Myndarsnið\",\n  \"ImgSavedClipboard\": \"Mynd vistuð til klemmispjalds\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Hafa með músarklikk\",\n  \"IncludeCursor\": \"Hafa músarbendil með\",\n  \"IncludeKeys\": \"Hafa lyklasnertingar með\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"Lyklasnertingar\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Tungumál\",\n  \"Left\": \"Vinstri\",\n  \"LoopbackSource\": \"Hátalaraúttaksuppspretta\",\n  \"MaxRecent\": \"Stærsti fjöldi til að halda eftir\",\n  \"MaxTextLength\": \"Lengsti texti\",\n  \"MicSource\": \"Hljóðnemauppspretta\",\n  \"Minimize\": \"Lágmarka\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Lágmarka til kerfisbakka\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"Músarklikk\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Nei\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"Ekki vistað\",\n  \"NoWebcam\": \"Engin vefmyndavél\",\n  \"Ok\": \"Allt í lagi\",\n  \"OnlyAudio\": \"Eingöngu hljóð\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"Opna úttagsmöppu\",\n  \"OutFolder\": \"Úttagsmappa\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Lykilorð\",\n  \"Paused\": \"Upptaka tímabundið stöðvuð\",\n  \"PauseResume\": \"Hlé | Endurræsa\",\n  \"PauseResumeRecording\": \"Gera hlé/Endurræsa upptöku\",\n  \"Port\": \"Tengi\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"Vefsel\",\n  \"Quality\": \"Gæði\",\n  \"Radius\": \"Radíus\",\n  \"Recent\": \"Nýtt\",\n  \"RecordStop\": \"Upptaka | Stöðva\",\n  \"Redo\": \"\",\n  \"Refresh\": \"Endurnýja\",\n  \"Region\": \"Svæði\",\n  \"RegionSelector\": \"Svæðisval\",\n  \"RemoveFromList\": \"Fjarlægja frá lista\",\n  \"Reset\": \"Endurræsa\",\n  \"Resize\": \"Breyta stærð\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Hægri\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Skjár\",\n  \"ScreenShot\": \"Skjáskot\",\n  \"ScreenShotActiveWindow\": \"Skjáskot virkur gluggi\",\n  \"ScreenShotDesktop\": \"Skjáskot skrifborð\",\n  \"ScreenShotSaved\": \"Skjáskot vistað\",\n  \"SelectFFmpegFolder\": \"Veldu FFmpeg möppu\",\n  \"SelectOutFolder\": \"Veldu frálagsmöppu\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Sýna tilkynningar\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Hefja/stöðva upptöku\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"Tímamörkum náð\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"Toppur\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Nota vefselssannvottun\",\n  \"UserName\": \"Notendanafn\",\n  \"VarFrameRate\": \"Breytileg rammatíðni\",\n  \"Video\": \"Myndband\",\n  \"VideoEncoder\": \"Myndbandsþýðari\",\n  \"VideoSaved\": \"Myndband vistað\",\n  \"VideoSource\": \"Myndbandsuppspretta\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Viltu þýða?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"Vefmyndavélssýn\",\n  \"Website\": \"\",\n  \"Window\": \"Gluggi\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Já\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/it.json",
    "content": "{\n  \"About\": \"Informazioni\",\n  \"AccentColor\": \"\",\n  \"Add\": \"Aggiungi\",\n  \"AlwaysOnTop\": \"Sempre in cima\",\n  \"Audio\": \"Audio\",\n  \"AudioFormat\": \"Formato Audio\",\n  \"AudioSaved\": \"Audio salvato\",\n  \"BackColor\": \"Colore di sfondo\",\n  \"BorderColor\": \"Colore bordo\",\n  \"BorderThickness\": \"Spessore bordo\",\n  \"Bottom\": \"Sotto\",\n  \"CaptureDuration\": \"Durata cattura (in secondi)\",\n  \"Center\": \"Centro\",\n  \"Changelog\": \"Registro modifiche\",\n  \"Clear\": \"Pulisci\",\n  \"ClearRecentList\": \"Pulisci lista recenti\",\n  \"Clipboard\": \"Appunti\",\n  \"Close\": \"Chiudi\",\n  \"Color\": \"Colore\",\n  \"ConfigCodecs\": \"Configura Codec\",\n  \"Configure\": \"Configura\",\n  \"CopyOutPathClipboard\": \"Copia il percorso di output nella clipboard\",\n  \"CopyPath\": \"Copia percorso\",\n  \"CopyToClipboard\": \"Copia nella clipboard\",\n  \"CornerRadius\": \"Raggio angolo\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"Ritaglia\",\n  \"CustomSize\": \"Dimensioni personalizzate\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"Tema Scuro\",\n  \"Delete\": \"Cancella\",\n  \"DiscardChanges\": \"Annulla Modifiche\",\n  \"Disk\": \"Disco\",\n  \"Donate\": \"Dona\",\n  \"DownloadFFmpeg\": \"Scarica FFmpeg\",\n  \"Edit\": \"Modifica\",\n  \"Elapsed\": \"Trascorso\",\n  \"ErrorOccurred\": \"Si è verificato un errore\",\n  \"Exit\": \"Esci\",\n  \"FFmpegFolder\": \"Cartella FFmpeg\",\n  \"FFmpegLog\": \"FFmpeg log\",\n  \"FileMenu\": \"File\",\n  \"FileMenuNew\": \"Nuovo\",\n  \"FileMenuOpen\": \"Apri\",\n  \"FileMenuSave\": \"Salva\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Grandezza font\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Schermo intero\",\n  \"HideOnFullScreenShot\": \"Nascondi negli screenshot a schermo intero\",\n  \"Host\": \"Host\",\n  \"Hotkeys\": \"Scorciatoie\",\n  \"ImageEditor\": \"Editor Immagine\",\n  \"ImgEmpty\": \"Non salvato. L'immagine acquisita è vuota\",\n  \"ImgFormat\": \"Formato immagine\",\n  \"ImgSavedClipboard\": \"Immagine salvata nella clipboard\",\n  \"ImageUploadFailed\": \"Caricamento immagine fallito\",\n  \"ImageUploadSuccess\": \"Immagine caricata con successo\",\n  \"ImageUploading\": \"Caricamento immagine\",\n  \"IncludeClicks\": \"Includi click mouse\",\n  \"IncludeCursor\": \"Includi cursore\",\n  \"IncludeKeys\": \"Includi KeyStrokes\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"Salva in file di testo separato\",\n  \"Language\": \"Lingua\",\n  \"Left\": \"Sinistra\",\n  \"LoopbackSource\": \"Sorgente speaker\",\n  \"MaxRecent\": \"Massimi elementi nella lista\",\n  \"MaxTextLength\": \"Massima lunghezza del testo\",\n  \"MicSource\": \"Sorgente microfono\",\n  \"Minimize\": \"Minimizza\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Minimizza nella system tray\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"Click del mouse\",\n  \"MouseMiddleClickColor\": \"Colore click centrale\",\n  \"MousePointer\": \"Puntatore del mouse\",\n  \"MouseRightClickColor\": \"Colore click destro\",\n  \"NewWindow\": \"\",\n  \"No\": \"No\",\n  \"None\": \"\",\n  \"Notifications\": \"Notifiche\",\n  \"NotSaved\": \"Non salvato\",\n  \"NoWebcam\": \"No webcam\",\n  \"Ok\": \"Ok\",\n  \"OnlyAudio\": \"Solo audio\",\n  \"Opacity\": \"Opacità\",\n  \"OpenFromClipboard\": \"Apri dagli Appunti\",\n  \"OpenOutFolder\": \"Apri cartella output\",\n  \"OutFolder\": \"Cartella output\",\n  \"Overlays\": \"Sovrapposizioni\",\n  \"Padding\": \"Rientro\",\n  \"Password\": \"Password\",\n  \"Paused\": \"Registrazione in pausa\",\n  \"PauseResume\": \"Pausa | Riprendi\",\n  \"PauseResumeRecording\": \"Pausa/Riprendi registrazione\",\n  \"Port\": \"Porta\",\n  \"Preview\": \"Anteprima\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Qualità\",\n  \"Radius\": \"Raggio\",\n  \"Recent\": \"Recenti\",\n  \"RecordStop\": \"Registra | Stop\",\n  \"Redo\": \"Ripeti\",\n  \"Refresh\": \"Ricarica\",\n  \"Region\": \"Regione\",\n  \"RegionSelector\": \"Selettore di regione\",\n  \"RemoveFromList\": \"Rimuovi dalla lista\",\n  \"Reset\": \"Azzera\",\n  \"Resize\": \"Ridimensiona\",\n  \"RestoreDefaults\": \"Ripristina predefiniti\",\n  \"Right\": \"Destra\",\n  \"SaveToClipboard\": \"Copia negli Appunti\",\n  \"Screen\": \"Schermo\",\n  \"ScreenShot\": \"\",\n  \"ScreenShotActiveWindow\": \"Screenshot della finestra attiva\",\n  \"ScreenShotDesktop\": \"Screenshot del desktop\",\n  \"ScreenShotSaved\": \"Screenshot salvato\",\n  \"SelectFFmpegFolder\": \"Seleziona la cartella FFmpeg\",\n  \"SelectOutFolder\": \"Selezione Cartella di output\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Mostra notifiche della system tray\",\n  \"SnapToWindow\": \"Aggancia alla Finestra\",\n  \"Sounds\": \"Suoni\",\n  \"StartStopRecording\": \"Inizia/Interrompi registrazione\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"Strumenti\",\n  \"Top\": \"Sopra\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"Taglia\",\n  \"Undo\": \"Annulla\",\n  \"UploadToImgur\": \"Carica su Imgur\",\n  \"UseProxyAuth\": \"Usa autenticazione proxy\",\n  \"UserName\": \"Nome utente\",\n  \"VarFrameRate\": \"Frame rate variabile\",\n  \"Video\": \"Video\",\n  \"VideoEncoder\": \"Video encoder\",\n  \"VideoSaved\": \"Video salvato\",\n  \"VideoSource\": \"Sorgente video\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"Mostra Licenze\",\n  \"ViewOnGitHub\": \"Vedi su GitHub\",\n  \"WantToTranslate\": \"Vuoi tradurre?\",\n  \"WebCam\": \"Webcam\",\n  \"WebCamSeparateFile\": \"Registra Webcam in file separato\",\n  \"WebCamView\": \"\",\n  \"Website\": \"Sito Web\",\n  \"Window\": \"Finestra\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Sì\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/ja.json",
    "content": "{\n  \"About\": \"バージョン情報\",\n  \"AccentColor\": \"アクセントカラー\",\n  \"Add\": \"追加\",\n  \"AlwaysOnTop\": \"常に前面に表示\",\n  \"Audio\": \"音声\",\n  \"AudioFormat\": \"音声フォーマット\",\n  \"AudioSaved\": \"音声が保存されました\",\n  \"BackColor\": \"背景色\",\n  \"BorderColor\": \"縁の色\",\n  \"BorderThickness\": \"縁の太さ\",\n  \"Bottom\": \"下部\",\n  \"CaptureDuration\": \"撮影時間(秒)\",\n  \"Center\": \"中央\",\n  \"Changelog\": \"バージョン履歴\",\n  \"Clear\": \"クリア\",\n  \"ClearRecentList\": \"最近使ったファイルのリストをクリア\",\n  \"Clipboard\": \"クリップボード\",\n  \"Close\": \"閉じる\",\n  \"Color\": \"色\",\n  \"ConfigCodecs\": \"コーデックの設定\",\n  \"Configure\": \"設定\",\n  \"CopyOutPathClipboard\": \"出力先パスをクリップボードにコピー\",\n  \"CopyPath\": \"パスをコピー\",\n  \"CopyToClipboard\": \"クリップボードにコピー\",\n  \"CornerRadius\": \"縁の半径\",\n  \"CrashLogs\": \"クラッシュログ\",\n  \"Crop\": \"クロップ\",\n  \"CustomSize\": \"任意のサイズ\",\n  \"CustomUrl\": \"任意のURL\",\n  \"DarkTheme\": \"ダークテーマ\",\n  \"Delete\": \"削除\",\n  \"DiscardChanges\": \"変更を破棄\",\n  \"Disk\": \"ディスク\",\n  \"Donate\": \"寄付\",\n  \"DownloadFFmpeg\": \"FFmpegをダウンロード\",\n  \"Edit\": \"編集\",\n  \"Elapsed\": \"経過\",\n  \"ErrorOccurred\": \"エラーが発生しました\",\n  \"Exit\": \"終了\",\n  \"FFmpegFolder\": \"FFmpegの場所\",\n  \"FFmpegLog\": \"FFmpegのログ\",\n  \"FileMenu\": \"ファイル\",\n  \"FileMenuNew\": \"新規\",\n  \"FileMenuOpen\": \"開く\",\n  \"FileMenuSave\": \"保存\",\n  \"FileNaming\": \"ファイル名\",\n  \"FontSize\": \"フォントの大きさ\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"全画面\",\n  \"HideOnFullScreenShot\": \"全画面スクリーンショット時に隠す\",\n  \"Host\": \"ホスト\",\n  \"Hotkeys\": \"ホットキー\",\n  \"ImageEditor\": \"画像エディター\",\n  \"ImgEmpty\": \"撮影された画像が空のため、保存されませんでした\",\n  \"ImgFormat\": \"画像の形式\",\n  \"ImgSavedClipboard\": \"クリップボードに保存された画像がコピーされました\",\n  \"ImageUploadFailed\": \"画像のアップロードに失敗しました...\",\n  \"ImageUploadSuccess\": \"画像のアップロードに成功しました。\",\n  \"ImageUploading\": \"画像をアップロード中です…\",\n  \"IncludeClicks\": \"マウスクリックを含める\",\n  \"IncludeCursor\": \"カーソルを含める\",\n  \"IncludeKeys\": \"キー入力を含める\",\n  \"Keymap\": \"キー割り当て\",\n  \"Keystrokes\": \"キー入力\",\n  \"KeystrokesHistoryCount\": \"履歴の数\",\n  \"KeystrokesHistorySpacing\": \"履歴の間隔\",\n  \"KeystrokesSeparateFile\": \"別のテキストファイルに保存する\",\n  \"Language\": \"言語\",\n  \"Left\": \"左\",\n  \"LoopbackSource\": \"スピーカーの出力元\",\n  \"MaxRecent\": \"最近使ったファイルに保持する数\",\n  \"MaxTextLength\": \"テキストの最大長\",\n  \"MicSource\": \"マイクの入力元\",\n  \"Minimize\": \"最小化\",\n  \"MinToTrayOnCaptureStart\": \"キャプチャ開始にトレイへ最小化\",\n  \"MinTray\": \"タスクバーに格納\",\n  \"MinTrayStartup\": \"起動時に最小化する\",\n  \"MinTrayClose\": \"閉じたらトレイも最小化する\",\n  \"MouseClicks\": \"マウスクリック\",\n  \"MouseMiddleClickColor\": \"真ん中のクリック色\",\n  \"MousePointer\": \"マウス ポインター\",\n  \"MouseRightClickColor\": \"右のクリック色\",\n  \"NewWindow\": \"新しいウインドウ\",\n  \"No\": \"いいえ\",\n  \"None\": \"なし\",\n  \"Notifications\": \"通知\",\n  \"NotSaved\": \"保存されません\",\n  \"NoWebcam\": \"ウェブカメラがありません\",\n  \"Ok\": \"OK\",\n  \"OnlyAudio\": \"音声のみ\",\n  \"Opacity\": \"透明度\",\n  \"OpenFromClipboard\": \"クリップボードから開く\",\n  \"OpenOutFolder\": \"出力先フォルダーを開く\",\n  \"OutFolder\": \"出力先フォルダー\",\n  \"Overlays\": \"オーバーレイ\",\n  \"Padding\": \"余白\",\n  \"Password\": \"パスワード\",\n  \"Paused\": \"録画を一時停止中\",\n  \"PauseResume\": \"一時停止 | 再開\",\n  \"PauseResumeRecording\": \"録画を一時停止/再開\",\n  \"Port\": \"ポート\",\n  \"Preview\": \"プレビュー\",\n  \"PreStartCountdown\": \"開始前のカウントダウン(秒)\",\n  \"Proxy\": \"プロキシ\",\n  \"Quality\": \"品質\",\n  \"Radius\": \"半径\",\n  \"Recent\": \"最近のファイル\",\n  \"RecordStop\": \"録画 | 停止\",\n  \"Redo\": \"やり直し\",\n  \"Refresh\": \"更新\",\n  \"Region\": \"地域\",\n  \"RegionSelector\": \"地域の選択\",\n  \"RemoveFromList\": \"リストから削除\",\n  \"Reset\": \"リセット\",\n  \"Resize\": \"サイズ変更\",\n  \"RestoreDefaults\": \"初期設定に戻す\",\n  \"Right\": \"右\",\n  \"SaveToClipboard\": \"クリップボードに保存\",\n  \"Screen\": \"画面\",\n  \"ScreenShot\": \"スクリーンショット\",\n  \"ScreenShotActiveWindow\": \"アクティブウィンドウを撮影\",\n  \"ScreenShotDesktop\": \"デスクトップを撮影\",\n  \"ScreenShotSaved\": \"スクリーンショットを保存しました\",\n  \"SelectFFmpegFolder\": \"FFmpegの場所\",\n  \"SelectOutFolder\": \"出力先の選択\",\n  \"SeparateAudioFiles\": \"オーディオソースごとに別々のファイル\",\n  \"ShowSysNotify\": \"タスクバーの通知を表示\",\n  \"SnapToWindow\": \"ウィンドウに合わせる\",\n  \"Sounds\": \"音声\",\n  \"StartStopRecording\": \"録画を開始/停止\",\n  \"StreamingKeys\": \"ストリームキー\",\n  \"Timeout\": \"タイムアウト\",\n  \"ToggleMouseClicks\": \"マウスクリックを切り替える\",\n  \"ToggleKeystrokes\": \"キー入力を切り替える\",\n  \"Tools\": \"ツール\",\n  \"Top\": \"トップ\",\n  \"TrayIcon\": \"トレイアイコン\",\n  \"Trim\": \"トリム\",\n  \"Undo\": \"元に戻す\",\n  \"UploadToImgur\": \"Imgur にアップロード\",\n  \"UseProxyAuth\": \"プロキシで認証を使用\",\n  \"UserName\": \"ユーザー名\",\n  \"VarFrameRate\": \"動的フレームレート\",\n  \"Video\": \"動画\",\n  \"VideoEncoder\": \"動画エンコーダー\",\n  \"VideoSaved\": \"動画が保存されました\",\n  \"VideoSource\": \"動画入力元\",\n  \"ViewCrashLogs\": \"クラッシュログの表示\",\n  \"ViewLicenses\": \"ライセンスを表示\",\n  \"ViewOnGitHub\": \"GitHubで表示する\",\n  \"WantToTranslate\": \"翻訳に協力しますか?\",\n  \"WebCam\": \"ウェブカメラ\",\n  \"WebCamSeparateFile\": \"別のファイルにWebカメラを録画する\",\n  \"WebCamView\": \"ウェブカメラの表示\",\n  \"Website\": \"ウェブサイト\",\n  \"Window\": \"ウィンドウ\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"はい\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/kab.json",
    "content": "{\n  \"About\": \"Ɣef\",\n  \"AccentColor\": \"Ini n useɣdebbu\",\n  \"Add\": \"Rnu\",\n  \"AlwaysOnTop\": \"Yalas nnig\",\n  \"Audio\": \"Ameslaw\",\n  \"AudioFormat\": \"Amasal ameslaw\",\n  \"AudioSaved\": \"Ameslaw yettwasekles\",\n  \"BackColor\": \"Ini n ugilal\",\n  \"BorderColor\": \"Ini n yiri\",\n  \"BorderThickness\": \"Tuzert n yiri\",\n  \"Bottom\": \"Ddaw\",\n  \"CaptureDuration\": \"Tanzagt n tuṭṭfa (s tasinin)\",\n  \"Center\": \"Ammas\",\n  \"Changelog\": \"Aɣmis n ibeddilen\",\n  \"Clear\": \"Sfeḍ\",\n  \"ClearRecentList\": \"Sfeḍ tabdart n melmi kan\",\n  \"Clipboard\": \"Tacfawit\",\n  \"Close\": \"Mdel\",\n  \"Color\": \"Ini\",\n  \"ConfigCodecs\": \"Swel ikudaken\",\n  \"Configure\": \"Swel\",\n  \"CopyOutPathClipboard\": \"Sukken abrid n ufaylu n tuffɣa ɣer tecfawit\",\n  \"CopyPath\": \"Sukken abrid\",\n  \"CopyToClipboard\": \"Sukken ɣer tecfawit\",\n  \"CornerRadius\": \"Aqqar n teɣmert\",\n  \"CrashLogs\": \"Aɣmis n iɣelluyen\",\n  \"Crop\": \"Ɣeẓ\",\n  \"CustomSize\": \"Tiddi yugnen\",\n  \"CustomUrl\": \"Url yugnen\",\n  \"DarkTheme\": \"Asentel aberkan\",\n  \"Delete\": \"Kkes\",\n  \"DiscardChanges\": \"Sefsex ibeddilen\",\n  \"Disk\": \"Aḍebsi\",\n  \"Donate\": \"Efk\",\n  \"DownloadFFmpeg\": \"Sider FFmpeg\",\n  \"Edit\": \"Ẓreg\",\n  \"Elapsed\": \"Yezri\",\n  \"ErrorOccurred\": \"Tella-d tuccḍa\",\n  \"Exit\": \"Ffeɣ\",\n  \"FFmpegFolder\": \"Akaram n FFmpeg\",\n  \"FFmpegLog\": \"Aɣmis n FFmpeg\",\n  \"FileMenu\": \"Afaylu\",\n  \"FileMenuNew\": \"Amaynut\",\n  \"FileMenuOpen\": \"Ldi\",\n  \"FileMenuSave\": \"Sekles\",\n  \"FileNaming\": \"Isem n ufaylu\",\n  \"FontSize\": \"Tiddi n tsefsit\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Agdil aččuran\",\n  \"HideOnFullScreenShot\": \"Ffer mi ara tili tuṭṭfa tummidt n ugdil\",\n  \"Host\": \"Asneftaɣ\",\n  \"Hotkeys\": \"Inegzumen\",\n  \"ImageEditor\": \"Amaẓrag n tugna\",\n  \"ImgEmpty\": \"Ur tettwasekles ara. Tugna yettwaṭṭfen d tilemt\",\n  \"ImgFormat\": \"Amasal n tugna\",\n  \"ImgSavedClipboard\": \"Tugna tettwasekles di tecfawit\",\n  \"ImageUploadFailed\": \"Asili n tugna yecceḍ\",\n  \"ImageUploadSuccess\": \"Asili n tugna yedda akken iwata\",\n  \"ImageUploading\": \"Asili n tugna\",\n  \"IncludeClicks\": \"Seddu isitiyen n tɣerdayt\",\n  \"IncludeCursor\": \"Seddu taḥnacaḍt\",\n  \"IncludeKeys\": \"Seddu inekcumen n unasiw\",\n  \"Keymap\": \"Tarusi n unasiw\",\n  \"Keystrokes\": \"Inekcumen n unasiw\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"Amazray n tallunt\",\n  \"KeystrokesSeparateFile\": \"Sekles ɣer ufaylu aḍris iberzen\",\n  \"Language\": \"Tutlayt\",\n  \"Left\": \"Zelmaḍ\",\n  \"LoopbackSource\": \"Aɣbalu n tuffɣa n imesmeɣren n imesli\",\n  \"MaxRecent\": \"Afella n iferdisen ara yeqqimen\",\n  \"MaxTextLength\": \"Tiddi tafellayt n uḍris\",\n  \"MicSource\": \"Aɣbalu n usawaḍ\",\n  \"Minimize\": \"Zimẓi\",\n  \"MinToTrayOnCaptureStart\": \"Simẓi di tazwara n tuṭṭfa\",\n  \"MinTray\": \"Simẓi di teɣzut n telɣut\",\n  \"MinTrayStartup\": \"Simẓi mi ara yekker\",\n  \"MinTrayClose\": \"Simẓi mi ara yemdel\",\n  \"MouseClicks\": \"Isitiyen n tɣerdayt\",\n  \"MouseMiddleClickColor\": \"Ini n usiti alemmas\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"Ini n usiti ayefus\",\n  \"NewWindow\": \"Asfaylu amaynut\",\n  \"No\": \"Ala\",\n  \"None\": \"Ulac\",\n  \"Notifications\": \"Ilɣuyen\",\n  \"NotSaved\": \"Ur yettwasekles ara\",\n  \"NoWebcam\": \"Ulac webcam\",\n  \"Ok\": \"IH\",\n  \"OnlyAudio\": \"Ameslaw kan\",\n  \"Opacity\": \"Tiḍullest\",\n  \"OpenFromClipboard\": \"Ldi si tecfawit\",\n  \"OpenOutFolder\": \"Ldi akaram n tuffɣa\",\n  \"OutFolder\": \"Akaram n tuffɣa\",\n  \"Overlays\": \"\",\n  \"Padding\": \"Tama tagensant\",\n  \"Password\": \"Awal n uɛeddi\",\n  \"Paused\": \"Asekles ibedd\",\n  \"PauseResume\": \"Seḥbes | Kemmel\",\n  \"PauseResumeRecording\": \"Sbedd/Kemmel asekles\",\n  \"Port\": \"Tawwurt\",\n  \"Preview\": \"Taskant\",\n  \"PreStartCountdown\": \"Amenḍar send tanekkra (s)\",\n  \"Proxy\": \"Apṛuksi\",\n  \"Quality\": \"Taɣara\",\n  \"Radius\": \"Aqqar\",\n  \"Recent\": \"Melmi kan\",\n  \"RecordStop\": \"Sekles | Bedd\",\n  \"Redo\": \"Err-d\",\n  \"Refresh\": \"Sismeḍ\",\n  \"Region\": \"Tamennaḍt\",\n  \"RegionSelector\": \"Amsefran n tmennaḍt\",\n  \"RemoveFromList\": \"Kkes tabdart\",\n  \"Reset\": \"Ales asekker\",\n  \"Resize\": \"Ales amsal\",\n  \"RestoreDefaults\": \"Err-d lexṣas\",\n  \"Right\": \"Yefus\",\n  \"SaveToClipboard\": \"Sekles di tecfawit\",\n  \"Screen\": \"Agdil\",\n  \"ScreenShot\": \"Tuṭṭfa n ugdil\",\n  \"ScreenShotActiveWindow\": \"Ṭṭef asfaylu urmid\",\n  \"ScreenShotDesktop\": \"Ṭṭef tanarit\",\n  \"ScreenShotSaved\": \"Tuṭṭfa n ugdil tettwasekles\",\n  \"SelectFFmpegFolder\": \"Fren akaram n FFmpeg\",\n  \"SelectOutFolder\": \"Fren akaram n tuffɣa\",\n  \"SeparateAudioFiles\": \"Ifuyla iberzen i yal aɣbalu ameslaw\",\n  \"ShowSysNotify\": \"Sken tilɣa\",\n  \"SnapToWindow\": \"Sezg ɣer tiddi n usfaylu\",\n  \"Sounds\": \"Imesla\",\n  \"StartStopRecording\": \"Bdu/Seḥbes asekles\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"Amenḍar afellay\",\n  \"ToggleMouseClicks\": \"Qluqel isitiyen n tɣerdayt\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"Ifecka\",\n  \"Top\": \"Nnig\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"Sezg\",\n  \"Undo\": \"Semmet\",\n  \"UploadToImgur\": \"Sili ɣer Imgur\",\n  \"UseProxyAuth\": \"Seqdec apṛuksi n usesteb\",\n  \"UserName\": \"Isem n useqdac\",\n  \"VarFrameRate\": \"Atug n tugna d ameskil\",\n  \"Video\": \"Avidyu\",\n  \"VideoEncoder\": \"Asettengal n uvidyu\",\n  \"VideoSaved\": \"Avidyu yettwasekles\",\n  \"VideoSource\": \"Aɣbalu avidyu\",\n  \"ViewCrashLogs\": \"Wali aɣmis n uɣelluy\",\n  \"ViewLicenses\": \"Wali turagin\",\n  \"ViewOnGitHub\": \"Wali di GitHub\",\n  \"WantToTranslate\": \"Tebɣiḍ ad tsuqqleḍ?\",\n  \"WebCam\": \"Takamirat n web\",\n  \"WebCamSeparateFile\": \"Sekles tawabkamt deg ufaylu iberzen\",\n  \"WebCamView\": \"Tamuɣli n webcam\",\n  \"Website\": \"Asmel n web\",\n  \"Window\": \"Asfaylu\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Ih\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/ko.json",
    "content": "{\n  \"About\": \"정보\",\n  \"AccentColor\": \"강조 색상\",\n  \"Add\": \"추가\",\n  \"AlwaysOnTop\": \"항상 최상위에 창 표시\",\n  \"Audio\": \"오디오\",\n  \"AudioFormat\": \"오디오 형식\",\n  \"AudioSaved\": \"오디오 저장됨\",\n  \"BackColor\": \"배경색\",\n  \"BorderColor\": \"테두리 색상\",\n  \"BorderThickness\": \"테두리 두께\",\n  \"Bottom\": \"맨 아래\",\n  \"CaptureDuration\": \"캡쳐 기간 (초)\",\n  \"Center\": \"가운데\",\n  \"Changelog\": \"변경 내역\",\n  \"Clear\": \"지우기\",\n  \"ClearRecentList\": \"최근 목록 지우기\",\n  \"Clipboard\": \"클립보드\",\n  \"Close\": \"닫기\",\n  \"Color\": \"색상\",\n  \"ConfigCodecs\": \"코덱 설정\",\n  \"Configure\": \"설정\",\n  \"CopyOutPathClipboard\": \"출력 파일 경로를 클립보드에 복사\",\n  \"CopyPath\": \"경로 복사\",\n  \"CopyToClipboard\": \"클립보드로 복사\",\n  \"CornerRadius\": \"가장자리 반지름\",\n  \"CrashLogs\": \"크래시 로그\",\n  \"Crop\": \"자르기\",\n  \"CustomSize\": \"사용자 지정 크기\",\n  \"CustomUrl\": \"사용자 지정 URL\",\n  \"DarkTheme\": \"어두운 테마\",\n  \"Delete\": \"삭제\",\n  \"DiscardChanges\": \"변경 내용 취소\",\n  \"Disk\": \"디스크\",\n  \"Donate\": \"후원하기\",\n  \"DownloadFFmpeg\": \"FFmpeg 다운로드\",\n  \"Edit\": \"편집\",\n  \"Elapsed\": \"경과\",\n  \"ErrorOccurred\": \"오류가 발생했습니다\",\n  \"Exit\": \"끝내기\",\n  \"FFmpegFolder\": \"FFmpeg 폴더\",\n  \"FFmpegLog\": \"FFmpeg 로그\",\n  \"FileMenu\": \"파일\",\n  \"FileMenuNew\": \"새 파일\",\n  \"FileMenuOpen\": \"열기\",\n  \"FileMenuSave\": \"저장\",\n  \"FileNaming\": \"파일명\",\n  \"FontSize\": \"글자 크기\",\n  \"FrameRate\": \"초당 프레임\",\n  \"FullScreen\": \"전체화면\",\n  \"HideOnFullScreenShot\": \"스크린샷에 창 숨기기\",\n  \"Host\": \"호스트\",\n  \"Hotkeys\": \"단축키\",\n  \"ImageEditor\": \"이미지 편집기\",\n  \"ImgEmpty\": \"저장되지 않음. 찍은 이미지가 비어 있습니다.\",\n  \"ImgFormat\": \"이미지 형식\",\n  \"ImgSavedClipboard\": \"이미지가 클립보드에 저장되었습니다.\",\n  \"ImageUploadFailed\": \"이미지 업로드 실패\",\n  \"ImageUploadSuccess\": \"이미지 업로드 성공\",\n  \"ImageUploading\": \"이미지 업로드 중\",\n  \"IncludeClicks\": \"마우스 클릭 포함\",\n  \"IncludeCursor\": \"커서 포함\",\n  \"IncludeKeys\": \"키 입력 포함\",\n  \"Keymap\": \"키맵\",\n  \"Keystrokes\": \" 키 입력\",\n  \"KeystrokesHistoryCount\": \"기록 수\",\n  \"KeystrokesHistorySpacing\": \"기록 간격\",\n  \"KeystrokesSeparateFile\": \"별도의 텍스트 파일에 저장\",\n  \"Language\": \"언어\",\n  \"Left\": \"왼쪽\",\n  \"LoopbackSource\": \"스피커 출력 소스\",\n  \"MaxRecent\": \"유지할 최대 항목\",\n  \"MaxTextLength\": \"최대 텍스트 길이\",\n  \"MicSource\": \"마이크 소스\",\n  \"Minimize\": \"최소화\",\n  \"MinToTrayOnCaptureStart\": \"캡쳐 시작 때 트레이로 최소화\",\n  \"MinTray\": \"시스템 트레이에 최소화\",\n  \"MinTrayStartup\": \"시작 시 트레이로 최소화\",\n  \"MinTrayClose\": \"종료 시 트레이로 최소화\",\n  \"MouseClicks\": \"마우스 클릭\",\n  \"MouseMiddleClickColor\": \"가운데 클릭 색상\",\n  \"MousePointer\": \"마우스 포인터\",\n  \"MouseRightClickColor\": \"우클릭 색상\",\n  \"NewWindow\": \"새 창\",\n  \"No\": \"아니오\",\n  \"None\": \"None\",\n  \"Notifications\": \"알림\",\n  \"NotSaved\": \"저장되지 않음\",\n  \"NoWebcam\": \"웹캠 사용하지 않음\",\n  \"Ok\": \"확인\",\n  \"OnlyAudio\": \"오디오만\",\n  \"Opacity\": \"불투명도\",\n  \"OpenFromClipboard\": \"클립보드에서 열기\",\n  \"OpenOutFolder\": \"저장 폴더 열기\",\n  \"OutFolder\": \"출력 폴더\",\n  \"Overlays\": \"오버레이\",\n  \"Padding\": \"Padding\",\n  \"Password\": \"비밀번호\",\n  \"Paused\": \"녹화 일시정지됨\",\n  \"PauseResume\": \"시작 | 정지\",\n  \"PauseResumeRecording\": \"녹화 시작/정지\",\n  \"Port\": \"포트\",\n  \"Preview\": \"미리보기\",\n  \"PreStartCountdown\": \"시작 전 카운트다운 (초)\",\n  \"Proxy\": \"프록시\",\n  \"Quality\": \"품질\",\n  \"Radius\": \"반지름\",\n  \"Recent\": \"최근 파일\",\n  \"RecordStop\": \"녹화 | 중지\",\n  \"Redo\": \"다시 실행\",\n  \"Refresh\": \"새로고침\",\n  \"Region\": \"영역 지정\",\n  \"RegionSelector\": \"영역 선택기\",\n  \"RemoveFromList\": \"목록에서 제거\",\n  \"Reset\": \"원래대로\",\n  \"Resize\": \"크기 조정\",\n  \"RestoreDefaults\": \"기본값 복원\",\n  \"Right\": \"오른쪽\",\n  \"SaveToClipboard\": \"클립보드에 저장\",\n  \"Screen\": \"스크린\",\n  \"ScreenShot\": \"스크린샷\",\n  \"ScreenShotActiveWindow\": \"활성 윈도우 스크린샷\",\n  \"ScreenShotDesktop\": \"바탕 화면 스크린샷\",\n  \"ScreenShotSaved\": \"스크린샷 저장됨\",\n  \"SelectFFmpegFolder\": \"FFmpeg 폴더 선택\",\n  \"SelectOutFolder\": \"출력 폴더 선택\",\n  \"SeparateAudioFiles\": \"모든 오디오 소스를 별도 파일로 저장\",\n  \"ShowSysNotify\": \"시스템 트레이 알림 표시\",\n  \"SnapToWindow\": \"창에 맞추기\",\n  \"Sounds\": \"소리\",\n  \"StartStopRecording\": \"녹화 시작/중지\",\n  \"StreamingKeys\": \"스트리밍 키\",\n  \"Timeout\": \"시간 제한\",\n  \"ToggleMouseClicks\": \"마우스 클릭 토글\",\n  \"ToggleKeystrokes\": \"키 입력 토글\",\n  \"Tools\": \"도구\",\n  \"Top\": \"맨 위\",\n  \"TrayIcon\": \"트레이 아이콘\",\n  \"Trim\": \"잘라내기\",\n  \"Undo\": \"실행 취소\",\n  \"UploadToImgur\": \"Imgur에 업로드\",\n  \"UseProxyAuth\": \"프록시 인증 사용\",\n  \"UserName\": \"사용지 이름\",\n  \"VarFrameRate\": \"가변 프레임\",\n  \"Video\": \"비디오\",\n  \"VideoEncoder\": \"비디오 인코더\",\n  \"VideoSaved\": \"비디오 저장됨\",\n  \"VideoSource\": \"비디오 소스\",\n  \"ViewCrashLogs\": \"크래시 로그 보기\",\n  \"ViewLicenses\": \"라이선스 보기\",\n  \"ViewOnGitHub\": \"GitHub에서 보기\",\n  \"WantToTranslate\": \"번역을 원하시나요?\",\n  \"WebCam\": \"웹캠\",\n  \"WebCamSeparateFile\": \"별도 파일에 웹캠 기록\",\n  \"WebCamView\": \"웹캠 뷰\",\n  \"Website\": \"웹사이트\",\n  \"Window\": \"창\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"네\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/ml.json",
    "content": "{\n  \"About\": \"വിവരം\",\n  \"AccentColor\": \"എടുത്തുകാണിക്കുന്ന നിറം\",\n  \"Add\": \"ചേര്‍ക്കുക\",\n  \"AlwaysOnTop\": \"വിൻഡോ എപ്പോഴും മുകളിൽ\",\n  \"Audio\": \"ഓഡിയോ\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"ഓഡിയോ സംരക്ഷിച്ചു\",\n  \"BackColor\": \"പിൻ നിറം\",\n  \"BorderColor\": \"ബോർഡർ നിറം\",\n  \"BorderThickness\": \"ബോർഡർ കനം\",\n  \"Bottom\": \"താഴെ\",\n  \"CaptureDuration\": \"ക്യാപ്ചർ ദൈർഘ്യം (sec)\",\n  \"Center\": \"മധ്യത്തിൽ\",\n  \"Changelog\": \"ചെയ്ഞ്ച്ലോഗ്\",\n  \"Clear\": \"മായ്ക്കുക\",\n  \"ClearRecentList\": \"സമീപകാല പട്ടിക മായ്ക്കുക\",\n  \"Clipboard\": \"ക്ലിപ്പ്ബോർഡ്\",\n  \"Close\": \"അടയ്ക്കുക\",\n  \"Color\": \"നിറം\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"ക്രമീകരിക്കുക\",\n  \"CopyOutPathClipboard\": \"ഔട്ട്പുട്ട് ഫയൽ പാത്ത് ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തുക\",\n  \"CopyPath\": \"ഫയൽ പാത്ത് പകർത്തുക\",\n  \"CopyToClipboard\": \"ക്ലിപ്പ്ബോർഡിലേയ്ക്ക് പകർത്തുക\",\n  \"CornerRadius\": \"മൂല ആരം\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"ക്രോപ്പുചെയ്യുക\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"ഇല്ലാതാക്കുക\",\n  \"DiscardChanges\": \"മാറ്റങ്ങൾ ഒഴിവാക്കുക\",\n  \"Disk\": \"ഡിസ്ക്\",\n  \"Donate\": \"സംഭാവനചെയ്യുക\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"ഒരു പിശക് സംഭവിച്ചു\",\n  \"Exit\": \"നിര്ഗമിക്കുക\",\n  \"FFmpegFolder\": \"FFmpeg ഫോൾഡർ\",\n  \"FFmpegLog\": \"FFmpeg ലോഗ്\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"പുതിയത്\",\n  \"FileMenuOpen\": \"തുറക്കുക\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"അക്ഷര വലിപ്പം\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"പൂർണ്ണ സ്ക്രീൻ\",\n  \"HideOnFullScreenShot\": \"പൂർണ്ണ സ്ക്രീൻ സ്ക്രീൻഷോട്ടിൽ വിൻഡോ മറയ്ക്കുക\",\n  \"Host\": \"ഹോസ്റ്റ്\",\n  \"Hotkeys\": \"ഹോട്ട്കീകൾ\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"സംരക്ഷിച്ചില്ല. എടുത്ത ചിത്രം ശൂന്യമായിരുന്നു\",\n  \"ImgFormat\": \"ഇമേജ് ഫോർമാറ്റ്\",\n  \"ImgSavedClipboard\": \"ചിത്രം ക്ലിപ്പ്ബോർഡിലേക്ക് സംരക്ഷിച്ചു\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"മൗസ് ക്ലിക്കുകൾ ഉൾപ്പെടുത്തു\",\n  \"IncludeCursor\": \"കഴ്സർ ഉൾപ്പെടുത്തു\",\n  \"IncludeKeys\": \"കീസ്ട്രോക്കുകൾ ഉൾപ്പെടുത്തു\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"കീസ്ട്രോക്കുകൾ\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"ഭാഷ\",\n  \"Left\": \"ഇടത് വശം\",\n  \"LoopbackSource\": \"സ്പീക്കർ ഔട്ട്പുട്ട് സോഴ്സ്\",\n  \"MaxRecent\": \"പരമാവധി ഇനങ്ങൾ\",\n  \"MaxTextLength\": \"പരമാവധി ടെക്സ്റ്റ് ദൈർഘ്യം\",\n  \"MicSource\": \"മൈക്രോഫോൺ ഉറവിടം\",\n  \"Minimize\": \"ചെറുതാക്കുക\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"സിസ്റ്റം ട്രേയിലേക്ക് ചെറുതാക്കുക\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"മൗസ് ക്ലിക്കുകൾ\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"അല്ല\",\n  \"None\": \"ഒന്നും അല്ല\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"സംരക്ഷിച്ചില്ല\",\n  \"NoWebcam\": \"വെബ്ക്യാം ഇല്ല\",\n  \"Ok\": \"ശരി\",\n  \"OnlyAudio\": \"ഓഡിയോ മാത്രം\",\n  \"Opacity\": \"ഒപ്പാസിറ്റി\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"ഔട്ട്പുട്ട് ഫോൾഡർ തുറക്കുക\",\n  \"OutFolder\": \"ഔട്ട്പുട്ട് ഫോൾഡർ\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"പാസ്വേഡ്\",\n  \"Paused\": \"റെക്കോർഡിംഗ് താൽക്കാലികമായി നിർത്തി\",\n  \"PauseResume\": \"താൽക്കാലികമായി നിർത്തുക | പുനരാരംഭിക്കുക\",\n  \"PauseResumeRecording\": \"റെക്കോർഡിംഗ് താൽക്കാലികമായി നിർത്തുക / പുനരാരംഭിക്കുക\",\n  \"Port\": \"പോർട്ട്\",\n  \"Preview\": \"പ്രിവ്യൂ കാണുക\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"പ്രോക്സി\",\n  \"Quality\": \"ഗുണനിലവാരം\",\n  \"Radius\": \"ആരം\",\n  \"Recent\": \"സമീപകാല\",\n  \"RecordStop\": \"റെക്കോർഡ് ചെയ്യുക | നിർത്തുക\",\n  \"Redo\": \"വീണ്ടും ചെയ്യുക\",\n  \"Refresh\": \"പുതുക്കുക\",\n  \"Region\": \"ഭാഗം\",\n  \"RegionSelector\": \"സെലക്ടർ\",\n  \"RemoveFromList\": \"ലിസ്റ്റിൽ നിന്നും നീക്കംചെയ്യുക\",\n  \"Reset\": \"പുനഃസജ്ജമാക്കുക\",\n  \"Resize\": \"വലിപ്പം മാറ്റുക\",\n  \"RestoreDefaults\": \"ഡിഫോൾട്ടുകൾ പുനഃസ്ഥാപിക്കുക\",\n  \"Right\": \"വലത് വശം\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"സ്ക്രീൻ\",\n  \"ScreenShot\": \"സ്ക്രീൻഷോട്ട്\",\n  \"ScreenShotActiveWindow\": \"സജീവ വിൻഡോയെ സ്ക്രീൻഷോട്ട് ചെയ്യുക\",\n  \"ScreenShotDesktop\": \"ഡെസ്ക്ടോപ്പ് സ്ക്രീൻഷോട്ട്\",\n  \"ScreenShotSaved\": \"സ്ക്രീൻഷോട്ട് സംരക്ഷിച്ചു\",\n  \"SelectFFmpegFolder\": \"FFMPEG ഫോൾഡർ തിരഞ്ഞെടുക്കുക\",\n  \"SelectOutFolder\": \"ഔട്ട്പുട്ട് ഫോൾഡർ തിരഞ്ഞെടുക്കുക\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"സിസ്റ്റം ട്രേ അറിയിപ്പുകൾ കാണിക്കുക\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"ശബ്ദങ്ങൾ\",\n  \"StartStopRecording\": \"റെക്കോർഡിംഗ് ആരംഭിക്കുക / നിർത്തുക\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"ടൈം ഔട്ട്\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"ഉപകരണങ്ങള്‍\",\n  \"Top\": \"മുകളിൽ\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"ട്രിം ചെയ്യുക\",\n  \"Undo\": \"പഴയപടിയാക്കുക\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"പ്രോക്സി പ്രാമാണീകരണം ഉപയോഗിക്കുക\",\n  \"UserName\": \"ഉപയോക്തൃനാമം\",\n  \"VarFrameRate\": \"വേരിയബിൾ ഫ്രെയിം റേറ്റ്\",\n  \"Video\": \"വീഡിയോ\",\n  \"VideoEncoder\": \"വീഡിയോ എൻകോഡർ\",\n  \"VideoSaved\": \"വീഡിയോ സംരക്ഷിച്ചു\",\n  \"VideoSource\": \"വീഡിയോ ഉറവിടം\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"തർജ്ജമ ചെയ്യാൻ ആഗ്രഹമുണ്ടോ?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"വെബ്ക്യാം കാണിക്കുക\",\n  \"Website\": \"\",\n  \"Window\": \"വിൻഡോ\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"അതെ\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/nl.json",
    "content": "{\n  \"About\": \"Over\",\n  \"AccentColor\": \"Accentkleur\",\n  \"Add\": \"Voeg toe\",\n  \"AlwaysOnTop\": \"Altijd Bovenaan\",\n  \"Audio\": \"Audio\",\n  \"AudioFormat\": \"Audioformaat\",\n  \"AudioSaved\": \"Audio Bewaard\",\n  \"BackColor\": \"Kleur Achterkant\",\n  \"BorderColor\": \"Kleur Rand\",\n  \"BorderThickness\": \"Dikte Rand\",\n  \"Bottom\": \"Onderkant\",\n  \"CaptureDuration\": \"Lengte Opname (in seconden)\",\n  \"Center\": \"Midden\",\n  \"Changelog\": \"Changelog\",\n  \"Clear\": \"Leegmaken\",\n  \"ClearRecentList\": \"Maak Recent Leeg\",\n  \"Clipboard\": \"Prikbord\",\n  \"Close\": \"Sluit\",\n  \"Color\": \"Kleur\",\n  \"ConfigCodecs\": \"Codecs configureren\",\n  \"Configure\": \"Stel In\",\n  \"CopyOutPathClipboard\": \"Kopieer Bestandslocatie van de Output naar het Prikbord\",\n  \"CopyPath\": \"Kopieer Bestandslocatie\",\n  \"CopyToClipboard\": \"Kopieer Naar Het Prikbord\",\n  \"CornerRadius\": \"Straal Hoeken\",\n  \"CrashLogs\": \"Crash Logs\",\n  \"Crop\": \"Bijsnijden\",\n  \"CustomSize\": \"Aangepaste grootte\",\n  \"CustomUrl\": \"Aangepaste Url\",\n  \"DarkTheme\": \"Donker thema\",\n  \"Delete\": \"Verwijder\",\n  \"DiscardChanges\": \"Wijzigingen negeren\",\n  \"Disk\": \"Schijf\",\n  \"Donate\": \"Doneer\",\n  \"DownloadFFmpeg\": \"FFmpeg downloaden\",\n  \"Edit\": \"Bewerk\",\n  \"Elapsed\": \"Verstreken\",\n  \"ErrorOccurred\": \"Er is iets fout gegaan\",\n  \"Exit\": \"Sluit\",\n  \"FFmpegFolder\": \"FFmpeg Map\",\n  \"FFmpegLog\": \"FFmpeg Log\",\n  \"FileMenu\": \"Bestand\",\n  \"FileMenuNew\": \"Nieuw\",\n  \"FileMenuOpen\": \"Openen\",\n  \"FileMenuSave\": \"Opslaan\",\n  \"FileNaming\": \"Bestandsnaam\",\n  \"FontSize\": \"Lettertype Grootte\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Volledig Scherm\",\n  \"HideOnFullScreenShot\": \"Verberg op Volledig Scherm Screenshot\",\n  \"Host\": \"Host\",\n  \"Hotkeys\": \"Sneltoetsen\",\n  \"ImageEditor\": \"Beeld Bewerker\",\n  \"ImgEmpty\": \"Niet Opgeslagen. Beeld was Leeg.\",\n  \"ImgFormat\": \"Beeldformaat\",\n  \"ImgSavedClipboard\": \"Beeld Opgeslagen naar het Prikbord\",\n  \"ImageUploadFailed\": \"Afbeelding Upload mislukt\",\n  \"ImageUploadSuccess\": \"Afbeelding Upload Succesvol\",\n  \"ImageUploading\": \"Afbeelding uploaden\",\n  \"IncludeClicks\": \"Gebruik Muiskliks\",\n  \"IncludeCursor\": \"Gebruik Cursor\",\n  \"IncludeKeys\": \"Gebruik Toetsaanslagen\",\n  \"Keymap\": \"Keymap\",\n  \"Keystrokes\": \"Toetsaanslagen\",\n  \"KeystrokesHistoryCount\": \"Geschiedenis tellen\",\n  \"KeystrokesHistorySpacing\": \"Geschiedenis afstand\",\n  \"KeystrokesSeparateFile\": \"Bewaar afzonderlijk txt bestand\",\n  \"Language\": \"Taal\",\n  \"Left\": \"Links\",\n  \"LoopbackSource\": \"Speaker Output Bron\",\n  \"MaxRecent\": \"Maximum Items op te slaan\",\n  \"MaxTextLength\": \"Maximum Tekst lengte\",\n  \"MicSource\": \"Microfoon Bron\",\n  \"Minimize\": \"Minimaliseer\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Minimaliseer naar Systeemvak\",\n  \"MinTrayStartup\": \"Minimaliseer naar SysTray bij opstarten\",\n  \"MinTrayClose\": \"Minimaliseer naar systray wanneer gesloten\",\n  \"MouseClicks\": \"Muisklikken\",\n  \"MouseMiddleClickColor\": \"Middle Click kleur\",\n  \"MousePointer\": \"Muisaanwijzer\",\n  \"MouseRightClickColor\": \"Rechter Click Kleur\",\n  \"NewWindow\": \"Nieuw Venster\",\n  \"No\": \"Geen\",\n  \"None\": \"Geen\",\n  \"Notifications\": \"Meldingen\",\n  \"NotSaved\": \"Niet Opgeslagen\",\n  \"NoWebcam\": \"Geen Webcam\",\n  \"Ok\": \"OK\",\n  \"OnlyAudio\": \"Alleen Audio\",\n  \"Opacity\": \"Transparantie\",\n  \"OpenFromClipboard\": \"Open van Klembord\",\n  \"OpenOutFolder\": \"Open Output Map\",\n  \"OutFolder\": \"Output Map\",\n  \"Overlays\": \"Maskers\",\n  \"Padding\": \"Afstand\",\n  \"Password\": \"Wachtwoord\",\n  \"Paused\": \"Opnemen Gepauzeerd\",\n  \"PauseResume\": \"Pauzeer | Hervatten\",\n  \"PauseResumeRecording\": \"Pauseer/Hervat Opnemen\",\n  \"Port\": \"Poort\",\n  \"Preview\": \"Voorvertoning\",\n  \"PreStartCountdown\": \"Voor aftellen (seconden)\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Kwaliteit\",\n  \"Radius\": \"Straal\",\n  \"Recent\": \"Recente\",\n  \"RecordStop\": \"Neem Op | Stop\",\n  \"Redo\": \"Opnieuw uitvoeren\",\n  \"Refresh\": \"Ververs\",\n  \"Region\": \"Regio\",\n  \"RegionSelector\": \"Regio Selector\",\n  \"RemoveFromList\": \"Verwijder Van Lijst\",\n  \"Reset\": \"Herstellen\",\n  \"Resize\": \"Pas Grootte Aan\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Rechts\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Scherm\",\n  \"ScreenShot\": \"\",\n  \"ScreenShotActiveWindow\": \"ScreenShot Actief Venster\",\n  \"ScreenShotDesktop\": \"ScreenShot Bureaublad\",\n  \"ScreenShotSaved\": \"ScreenShot Opgeslagen\",\n  \"SelectFFmpegFolder\": \"Selecteer FFmpeg Map\",\n  \"SelectOutFolder\": \"Selecteer Output Map\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Laat Systeemvak Notificaties zien\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Start/Stop Opnemen\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"Bovenkant\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Gebruik Proxy Authenticatie\",\n  \"UserName\": \"Gebruikersnaam\",\n  \"VarFrameRate\": \"Variabele Frame Rate\",\n  \"Video\": \"\",\n  \"VideoEncoder\": \"\",\n  \"VideoSaved\": \"Video Opgeslagen\",\n  \"VideoSource\": \"Video Bron\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Wil je helpen vertalen?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"\",\n  \"Website\": \"\",\n  \"Window\": \"Venster\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Ja\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/no.json",
    "content": "{\n  \"About\": \"Om\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"Alltid øverst\",\n  \"Audio\": \"Lyd\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Lyd lagret\",\n  \"BackColor\": \"Bakgrunnsfarge\",\n  \"BorderColor\": \"Rammefarge\",\n  \"BorderThickness\": \"Rammetykkelse\",\n  \"Bottom\": \"Bunn\",\n  \"CaptureDuration\": \"Opptaksvarighet (i sekunder)\",\n  \"Center\": \"Midten\",\n  \"Changelog\": \"Endringslogg\",\n  \"Clear\": \"Tøm\",\n  \"ClearRecentList\": \"Tøm historikk\",\n  \"Clipboard\": \"Utklippstavle\",\n  \"Close\": \"Lukk\",\n  \"Color\": \"Farge\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Konfigurer\",\n  \"CopyOutPathClipboard\": \"Kopier output-filsti til utklippstavle\",\n  \"CopyPath\": \"Kopi filsti\",\n  \"CopyToClipboard\": \"Kopier til utklippstavle\",\n  \"CornerRadius\": \"Hjørneradius\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Slett\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"Harddisk\",\n  \"Donate\": \"Doner\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"En feil oppsto\",\n  \"Exit\": \"Avslutt\",\n  \"FFmpegFolder\": \"FFmpeg-mappe\",\n  \"FFmpegLog\": \"FFmpeg-logg\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Skriftstørrelse\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"Fullskjerm\",\n  \"HideOnFullScreenShot\": \"Skjul for fullskjerm skjermbilde\",\n  \"Host\": \"Vert\",\n  \"Hotkeys\": \"Hurtigtaster\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Ikke lagret. Bildet var tomt\",\n  \"ImgFormat\": \"Bildeformat\",\n  \"ImgSavedClipboard\": \"Bilde lagret til utklippstavle\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Inkluder museklikk\",\n  \"IncludeCursor\": \"Inkluder musepeker\",\n  \"IncludeKeys\": \"Inkluder tastetrykk\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"Tastetrykk\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Språk\",\n  \"Left\": \"Venstre\",\n  \"LoopbackSource\": \"Lydkilde\",\n  \"MaxRecent\": \"Maks antall filer\",\n  \"MaxTextLength\": \"Maks tekstlengde\",\n  \"MicSource\": \"Mikrofonkilde\",\n  \"Minimize\": \"Minimer\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Minimer til oppgavelinjen\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"Museklikk\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Nei\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"Ikke lagret\",\n  \"NoWebcam\": \"Ingen webkamera\",\n  \"Ok\": \"Ok\",\n  \"OnlyAudio\": \"Kun lyd\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"Åpne output-mappe\",\n  \"OutFolder\": \"Output-mappe\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Passord\",\n  \"Paused\": \"Opptak pauset\",\n  \"PauseResume\": \"\",\n  \"PauseResumeRecording\": \"Pause/Fortsett opptak\",\n  \"Port\": \"\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"\",\n  \"Quality\": \"Kvalitet\",\n  \"Radius\": \"\",\n  \"Recent\": \"Nylig\",\n  \"RecordStop\": \"Opptak | Stopp\",\n  \"Redo\": \"\",\n  \"Refresh\": \"Oppdater\",\n  \"Region\": \"\",\n  \"RegionSelector\": \"Velg region\",\n  \"RemoveFromList\": \"Fjern fra liste\",\n  \"Reset\": \"Nullstill\",\n  \"Resize\": \"Tilpass størrelse\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Høyre\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Skjerm\",\n  \"ScreenShot\": \"Skjermbilde\",\n  \"ScreenShotActiveWindow\": \"Skjermbilde av aktivt vindu\",\n  \"ScreenShotDesktop\": \"Skjermbilde av skrivebord\",\n  \"ScreenShotSaved\": \"Skjermbilde lagret\",\n  \"SelectFFmpegFolder\": \"Velg FFmpeg-mapp\",\n  \"SelectOutFolder\": \"Velg output-mappe\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Vis oppgavelinje notifikasjoner\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Start/Stop Opptak\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"Topp\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Bruk proxyautentisering\",\n  \"UserName\": \"Brukernavn\",\n  \"VarFrameRate\": \"Variabel bildefrekvens\",\n  \"Video\": \"\",\n  \"VideoEncoder\": \"Video-encoder\",\n  \"VideoSaved\": \"Video lagret\",\n  \"VideoSource\": \"Videokilde\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Vil du oversette?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"Webkamera visning\",\n  \"Website\": \"\",\n  \"Window\": \"Vindu\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Ja\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/pl.json",
    "content": "{\n  \"About\": \"O programie\",\n  \"AccentColor\": \"Kolor interfejsu\",\n  \"Add\": \"Dodaj\",\n  \"AlwaysOnTop\": \"Zawsze na wierzchu\",\n  \"Audio\": \"Dźwięk\",\n  \"AudioFormat\": \"Format dźwięku\",\n  \"AudioSaved\": \"Zapisano dźwięk\",\n  \"BackColor\": \"Kolor tła\",\n  \"BorderColor\": \"Kolor ramki\",\n  \"BorderThickness\": \"Grubość ramki\",\n  \"Bottom\": \"Dół\",\n  \"CaptureDuration\": \"Okres przechwytywania (w sekundach)\",\n  \"Center\": \"Środek\",\n  \"Changelog\": \"Lista zmian\",\n  \"Clear\": \"Wyczyść\",\n  \"ClearRecentList\": \"Wyczyść ostatnie\",\n  \"Clipboard\": \"Schowek\",\n  \"Close\": \"Zamknij\",\n  \"Color\": \"Kolor\",\n  \"ConfigCodecs\": \"Konfiguracja kodeków\",\n  \"Configure\": \"Konfiguracja\",\n  \"CopyOutPathClipboard\": \"Kopiuj do schowka ścieżkę pliku wyjściowego\",\n  \"CopyPath\": \"Kopiuj ścieżkę\",\n  \"CopyToClipboard\": \"Kopiuj do schowka\",\n  \"CornerRadius\": \"Promień narożnika\",\n  \"CrashLogs\": \"Dzienniki awarii\",\n  \"Crop\": \"Kadrowanie\",\n  \"CustomSize\": \"Własny rozmiar\",\n  \"CustomUrl\": \"Własny adres\",\n  \"DarkTheme\": \"Ciemny motyw\",\n  \"Delete\": \"Usuń\",\n  \"DiscardChanges\": \"Odrzuć zmiany\",\n  \"Disk\": \"Dysk\",\n  \"Donate\": \"Wesprzyj nas\",\n  \"DownloadFFmpeg\": \"Pobierz kodek FFmpeg\",\n  \"Edit\": \"Edycja\",\n  \"Elapsed\": \"Upłynęło\",\n  \"ErrorOccurred\": \"Wystąpił błąd\",\n  \"Exit\": \"Wyjdź\",\n  \"FFmpegFolder\": \"Katalog kodeka FFmpeg\",\n  \"FFmpegLog\": \"Log kodeka FFmpeg\",\n  \"FileMenu\": \"Plik\",\n  \"FileMenuNew\": \"Nowy\",\n  \"FileMenuOpen\": \"Otwórz\",\n  \"FileMenuSave\": \"Zapisz\",\n  \"FileNaming\": \"Nazwa pliku\",\n  \"FontSize\": \"Rozmiar czcionki\",\n  \"FrameRate\": \"kl./s\",\n  \"FullScreen\": \"Pełny ekran\",\n  \"HideOnFullScreenShot\": \"Ukryj przy zrzucie pełnoekranowym\",\n  \"Host\": \"Host\",\n  \"Hotkeys\": \"Skróty klawiszowe\",\n  \"ImageEditor\": \"Edytor obrazu\",\n  \"ImgEmpty\": \"Nie zapisano. Obraz był pusty\",\n  \"ImgFormat\": \"Format obrazu\",\n  \"ImgSavedClipboard\": \"Zapisano obraz do schowka\",\n  \"ImageUploadFailed\": \"Wysyłanie obrazu nie powiodło się\",\n  \"ImageUploadSuccess\": \"Wysyłanie obrazu powiodło się\",\n  \"ImageUploading\": \"Wysyłanie obrazu\",\n  \"IncludeClicks\": \"Pokaż kliknięcia myszy\",\n  \"IncludeCursor\": \"Pokaż kursor myszy\",\n  \"IncludeKeys\": \"Pokaż naciśnięcia klawiszy\",\n  \"Keymap\": \"Mapa klawiszy\",\n  \"Keystrokes\": \"Naciśnięcia klawiszy\",\n  \"KeystrokesHistoryCount\": \"Długość historii\",\n  \"KeystrokesHistorySpacing\": \"Rozstaw elementów historii\",\n  \"KeystrokesSeparateFile\": \"Zapisz do odrębnego pliku tekstowego\",\n  \"Language\": \"Język\",\n  \"Left\": \"Lewo\",\n  \"LoopbackSource\": \"Wyjście dźwięku\",\n  \"MaxRecent\": \"Zachowaj maksymalnie\",\n  \"MaxTextLength\": \"Maksymalna długość tekstu\",\n  \"MicSource\": \"Wejście dźwięku\",\n  \"Minimize\": \"Minimalizuj\",\n  \"MinToTrayOnCaptureStart\": \"Minimalizuj do zasobnika przy rozpoczęciu przechwytywania\",\n  \"MinTray\": \"Minimalizuj do zasobnika systemowego\",\n  \"MinTrayStartup\": \"Minimalizuj do zasobnika przy starcie\",\n  \"MinTrayClose\": \"Minimalizuj do zasobnika przy zamknięciu\",\n  \"MouseClicks\": \"Kliknięcia myszy\",\n  \"MouseMiddleClickColor\": \"Kolor wciśnięcia środkowego przycisku myszki\",\n  \"MousePointer\": \"Wskaźnik myszy\",\n  \"MouseRightClickColor\": \"Kolor wciśnięcia prawego przycisku myszki\",\n  \"NewWindow\": \"Nowe okno\",\n  \"No\": \"Nie\",\n  \"None\": \"Brak\",\n  \"Notifications\": \"Powiadomienia\",\n  \"NotSaved\": \"Nie zapisano\",\n  \"NoWebcam\": \"Brak kamery internetowej\",\n  \"Ok\": \"Ok\",\n  \"OnlyAudio\": \"Tylko dźwięk\",\n  \"Opacity\": \"Nieprzezroczystość\",\n  \"OpenFromClipboard\": \"Otwórz ze schowka\",\n  \"OpenOutFolder\": \"Otwórz katalog wyjściowy\",\n  \"OutFolder\": \"Katalog wyjściowy\",\n  \"Overlays\": \"Nakładki\",\n  \"Padding\": \"Dopełnienie\",\n  \"Password\": \"Hasło\",\n  \"Paused\": \"Nagrywanie wstrzymane\",\n  \"PauseResume\": \"Wstrzymaj | Wznów\",\n  \"PauseResumeRecording\": \"Wstrzymaj/Wznów nagrywanie\",\n  \"Port\": \"Port\",\n  \"Preview\": \"Podgląd\",\n  \"PreStartCountdown\": \"Opóźnienie zapisu (w sekundach)\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Jakość\",\n  \"Radius\": \"Promień\",\n  \"Recent\": \"Ostatnie\",\n  \"RecordStop\": \"Nagrywaj | Zakończ\",\n  \"Redo\": \"Wykonaj ponownie\",\n  \"Refresh\": \"Odśwież\",\n  \"Region\": \"Obszar\",\n  \"RegionSelector\": \"Wybór obszaru\",\n  \"RemoveFromList\": \"Usuń z listy\",\n  \"Reset\": \"Zresetuj\",\n  \"Resize\": \"Zmień rozmiar\",\n  \"RestoreDefaults\": \"Przywróć domyślne\",\n  \"Right\": \"Prawo\",\n  \"SaveToClipboard\": \"Zapisz do schowka\",\n  \"Screen\": \"Ekran\",\n  \"ScreenShot\": \"Zrzut ekranu\",\n  \"ScreenShotActiveWindow\": \"Zrzut ekranu aktywnego okna\",\n  \"ScreenShotDesktop\": \"Zrzut ekranu pulpitu\",\n  \"ScreenShotSaved\": \"Zapisano zrzut ekranu\",\n  \"SelectFFmpegFolder\": \"Wybierz katalog FFmpeg\",\n  \"SelectOutFolder\": \"Wybierz katalog wyjściowy\",\n  \"SeparateAudioFiles\": \"Odrębny plik dla każdego źródła dźwięku\",\n  \"ShowSysNotify\": \"Pokaż powiadomienia w zasobniku systemowym\",\n  \"SnapToWindow\": \"Przyciągaj do okna\",\n  \"Sounds\": \"Dzwięki\",\n  \"StartStopRecording\": \"Rozpocznij/Zakończ nagrywanie\",\n  \"StreamingKeys\": \"Klucze do streamów\",\n  \"Timeout\": \"Przekroczono czas\",\n  \"ToggleMouseClicks\": \"Pokaż kliknięcia myszy\",\n  \"ToggleKeystrokes\": \"Pokaż naciśnięcia klawiszy\",\n  \"Tools\": \"Narzędzia\",\n  \"Top\": \"Góra\",\n  \"TrayIcon\": \"Ikona w zasobniku systemowym\",\n  \"Trim\": \"Przytnij\",\n  \"Undo\": \"Cofnij\",\n  \"UploadToImgur\": \"Wyślij do Imgur\",\n  \"UseProxyAuth\": \"Użyj uwierzytelnienia proxy\",\n  \"UserName\": \"Nazwa użytkownika\",\n  \"VarFrameRate\": \"Zmienna ilość klatek na sekundę\",\n  \"Video\": \"Wideo\",\n  \"VideoEncoder\": \"Kodowanie wideo\",\n  \"VideoSaved\": \"Zapisano wideo\",\n  \"VideoSource\": \"Źródło wideo\",\n  \"ViewCrashLogs\": \"Zobacz dzienniki awarii\",\n  \"ViewLicenses\": \"Zobacz licencje\",\n  \"ViewOnGitHub\": \"Zobacz na GitHub\",\n  \"WantToTranslate\": \"Chcesz pomóc w tłumaczeniu?\",\n  \"WebCam\": \"Kamera internetowa\",\n  \"WebCamSeparateFile\": \"Nagraj kamerę internetową do odrębnego pliku\",\n  \"WebCamView\": \"Podgląd kamery internetowej\",\n  \"Website\": \"Witryna internetowa\",\n  \"Window\": \"Okno\",\n  \"WindowScreenShotTransparency\": \"Przezroczystość zrzutu ekranu\",\n  \"Yes\": \"Tak\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/pt-BR.json",
    "content": "{\n  \"About\": \"Sobre\",\n  \"AccentColor\": \"Cor de Destaque\",\n  \"Add\": \"Adicionar\",\n  \"AlwaysOnTop\": \"Sempre no Topo\",\n  \"Audio\": \"Áudio\",\n  \"AudioFormat\": \"Formato de Áudio\",\n  \"AudioSaved\": \"Áudio Salvo\",\n  \"BackColor\": \"Cor de Fundo\",\n  \"BorderColor\": \"Cor da Borda\",\n  \"BorderThickness\": \"Espessura da Borda\",\n  \"Bottom\": \"Margem Inferior\",\n  \"CaptureDuration\": \"Duração da Captura (em segundos)\",\n  \"Center\": \"Centro\",\n  \"Changelog\": \"Relatório de Mudanças\",\n  \"Clear\": \"Apagar\",\n  \"ClearRecentList\": \"Apagar Lista Recente\",\n  \"Clipboard\": \"Área de Transferência\",\n  \"Close\": \"Fechar\",\n  \"Color\": \"Cor\",\n  \"ConfigCodecs\": \"Configurar Codecs\",\n  \"Configure\": \"Configurar\",\n  \"CopyOutPathClipboard\": \"Copiar o local do arquivo para a área de transferência\",\n  \"CopyPath\": \"Copiar Local\",\n  \"CopyToClipboard\": \"Copiar para Área de Transferência\",\n  \"CornerRadius\": \"Raio da quina\",\n  \"CrashLogs\": \"Relatório de Erros\",\n  \"Crop\": \"Recortar\",\n  \"CustomSize\": \"Tamanho Personalizado\",\n  \"CustomUrl\": \"Url Personalizada\",\n  \"DarkTheme\": \"Tema Escuro\",\n  \"Delete\": \"Apagar\",\n  \"DiscardChanges\": \"Descartar Alterações\",\n  \"Disk\": \"Disco\",\n  \"Donate\": \"Faça uma doação\",\n  \"DownloadFFmpeg\": \"Baixar FFmpeg\",\n  \"Edit\": \"Editar\",\n  \"Elapsed\": \"Transcorrido\",\n  \"ErrorOccurred\": \"Ocorreu um Erro\",\n  \"Exit\": \"Sair\",\n  \"FFmpegFolder\": \"Pasta do FFmpeg\",\n  \"FFmpegLog\": \"Relatório do FFmpeg\",\n  \"FileMenu\": \"Arquivo\",\n  \"FileMenuNew\": \"Novo\",\n  \"FileMenuOpen\": \"Abrir\",\n  \"FileMenuSave\": \"Salvar\",\n  \"FileNaming\": \"Nome do Arquivo\",\n  \"FontSize\": \"Tamanho da Fonte\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Tela Cheia\",\n  \"HideOnFullScreenShot\": \"Ocultar na Captura em Tela Cheia\",\n  \"Host\": \"Servidor\",\n  \"Hotkeys\": \"Teclas de Atalho\",\n  \"ImageEditor\": \"Editor de Imagem\",\n  \"ImgEmpty\": \"Não salvo, a imagem capturada estava vazia\",\n  \"ImgFormat\": \"Formato de Imagem\",\n  \"ImgSavedClipboard\": \"Imagem copiada para Área de Transferência\",\n  \"ImageUploadFailed\": \"Falha no upload da imagem\",\n  \"ImageUploadSuccess\": \"Imagem enviada com sucesso\",\n  \"ImageUploading\": \"Upload de imagem\",\n  \"IncludeClicks\": \"Incluir Cliques do Mouse\",\n  \"IncludeCursor\": \"Incluir Cursor\",\n  \"IncludeKeys\": \"Incluir Teclas Pressionadas\",\n  \"Keymap\": \"Mapa de Teclado\",\n  \"Keystrokes\": \"Teclas Pressionadas\",\n  \"KeystrokesHistoryCount\": \"Contador de Histórico\",\n  \"KeystrokesHistorySpacing\": \"Espaçamento do Histórico\",\n  \"KeystrokesSeparateFile\": \"Salvar Separado em Arquivo de Texto\",\n  \"Language\": \"Idioma\",\n  \"Left\": \"Esquerda\",\n  \"LoopbackSource\": \"Fonte de Saída do Alto-falante\",\n  \"MaxRecent\": \"Máximo de itens para manter\",\n  \"MaxTextLength\": \"Comprimento Máximo do Texto\",\n  \"MicSource\": \"Fonte do Microfone\",\n  \"Minimize\": \"Minimizar\",\n  \"MinToTrayOnCaptureStart\": \"Minimizar ao Iniciar a Captura\",\n  \"MinTray\": \"Minimizar para a Área de Notificação\",\n  \"MinTrayStartup\": \"Minimizar para a Área de Notificação quando Iniciar\",\n  \"MinTrayClose\": \"Minimizar para a Área de Notificação quando Fechar\",\n  \"MouseClicks\": \"Cliques do Mouse\",\n  \"MouseMiddleClickColor\": \"Cor do Clique do Botão do Meio\",\n  \"MousePointer\": \"Ponteiro do Mouse\",\n  \"MouseRightClickColor\": \"Cor do Botão Direito\",\n  \"NewWindow\": \"Em uma nova Janela\",\n  \"No\": \"Não\",\n  \"None\": \"Nenhum\",\n  \"Notifications\": \"Notificações\",\n  \"NotSaved\": \"Não salvo\",\n  \"NoWebcam\": \"Nenhuma Webcam\",\n  \"Ok\": \"OK\",\n  \"OnlyAudio\": \"Apenas Áudio\",\n  \"Opacity\": \"Transparência\",\n  \"OpenFromClipboard\": \"Importar da Área de Transferência\",\n  \"OpenOutFolder\": \"Abrir Pasta de Saída\",\n  \"OutFolder\": \"Pasta de Saída\",\n  \"Overlays\": \"Sobreposição\",\n  \"Padding\": \"Preenchimento\",\n  \"Password\": \"Senha\",\n  \"Paused\": \"Gravação Pausada\",\n  \"PauseResume\": \"Pausar | Continuar\",\n  \"PauseResumeRecording\": \"Pausar/Continuar Gravação\",\n  \"Port\": \"Porta\",\n  \"Preview\": \"Pré-visualizar\",\n  \"PreStartCountdown\": \"Contagem Regressiva (em segundos)\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Qualidade\",\n  \"Radius\": \"Alcance\",\n  \"Recent\": \"Recente\",\n  \"RecordStop\": \"Gravar | Parar\",\n  \"Redo\": \"Repetir\",\n  \"Refresh\": \"Atualizar\",\n  \"Region\": \"Região\",\n  \"RegionSelector\": \"Selecionar Região\",\n  \"RemoveFromList\": \"Remover da Lista\",\n  \"Reset\": \"Reiniciar\",\n  \"Resize\": \"Redimensionar\",\n  \"RestoreDefaults\": \"Restaurar Padrões\",\n  \"Right\": \"Direita\",\n  \"SaveToClipboard\": \"Copiar para Área de Transferência\",\n  \"Screen\": \"Tela\",\n  \"ScreenShot\": \"Captura de Tela\",\n  \"ScreenShotActiveWindow\": \"Capturar Janela Ativa\",\n  \"ScreenShotDesktop\": \"Capturar Área de Trabalho\",\n  \"ScreenShotSaved\": \"Captura Salva\",\n  \"SelectFFmpegFolder\": \"Selecione a Pasta do FFmpeg\",\n  \"SelectOutFolder\": \"Selecione a Pasta de Saída\",\n  \"SeparateAudioFiles\": \"Arquivo separado para cada fonte de áudio\",\n  \"ShowSysNotify\": \"Exibir Mensagens na Área de Notificação\",\n  \"SnapToWindow\": \"Encaixar na Janela\",\n  \"Sounds\": \"Sons\",\n  \"StartStopRecording\": \"Iniciar/Parar Gravação\",\n  \"StreamingKeys\": \"Chave da Transmissão\",\n  \"Timeout\": \"Tempo Limite\",\n  \"ToggleMouseClicks\": \"Incluir Cliques do Mouse\",\n  \"ToggleKeystrokes\": \"Incluir Teclas Pressionadas\",\n  \"Tools\": \"Ferramentas\",\n  \"Top\": \"Topo\",\n  \"TrayIcon\": \"Ícone da Bandeja\",\n  \"Trim\": \"Cortar\",\n  \"Undo\": \"Desfazer\",\n  \"UploadToImgur\": \"Enviar para Imgur\",\n  \"UseProxyAuth\": \"Usar Autenticação de Proxy\",\n  \"UserName\": \"Nome de Usuário\",\n  \"VarFrameRate\": \"Taxa de Quadros Variável\",\n  \"Video\": \"Vídeo\",\n  \"VideoEncoder\": \"Codificador de Vídeo\",\n  \"VideoSaved\": \"Vídeo Salvo\",\n  \"VideoSource\": \"Fonte de Vídeo\",\n  \"ViewCrashLogs\": \"Visualizar Relatório de Erros\",\n  \"ViewLicenses\": \"Visualizar licenças\",\n  \"ViewOnGitHub\": \"Ver no GitHub\",\n  \"WantToTranslate\": \"Gostaria de Traduzir?\",\n  \"WebCam\": \"Webcam\",\n  \"WebCamSeparateFile\": \"Gravar Webcam em Arquivo Separado\",\n  \"WebCamView\": \"Visualização da Webcam\",\n  \"Website\": \"Site na Web\",\n  \"Window\": \"Janela\",\n  \"WindowScreenShotTransparency\": \"Capturas de Tela no modo Janela devem ser Transparentes\",\n  \"Yes\": \"Sim\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/pt.json",
    "content": "{\n  \"About\": \"Sobre\",\n  \"AccentColor\": \"Cor de realces\",\n  \"Add\": \"Adicionar\",\n  \"AlwaysOnTop\": \"Sempre no topo\",\n  \"Audio\": \"Áudio\",\n  \"AudioFormat\": \"Formato de áudio\",\n  \"AudioSaved\": \"Áudio guardado\",\n  \"BackColor\": \"Cor de fundo\",\n  \"BorderColor\": \"Cor da borda\",\n  \"BorderThickness\": \"Espessura da borda\",\n  \"Bottom\": \"Em baixo\",\n  \"CaptureDuration\": \"Duração da captura (em segundos)\",\n  \"Center\": \"Centro\",\n  \"Changelog\": \"Registo de alterações\",\n  \"Clear\": \"Limpar\",\n  \"ClearRecentList\": \"Limpar lista de recentes\",\n  \"Clipboard\": \"Área de transferência\",\n  \"Close\": \"Fechar\",\n  \"Color\": \"Cor\",\n  \"ConfigCodecs\": \"Configurar Codecs\",\n  \"Configure\": \"Configurar\",\n  \"CopyOutPathClipboard\": \"Copiar caminho de saída do ficheiro para a área de transferência\",\n  \"CopyPath\": \"Copiar caminho\",\n  \"CopyToClipboard\": \"Copiar para área de transferência\",\n  \"CornerRadius\": \"Raio do canto\",\n  \"CrashLogs\": \"Registo de incidentes\",\n  \"Crop\": \"Recortar\",\n  \"CustomSize\": \"Tamanho personalizado\",\n  \"CustomUrl\": \"URL personalizado\",\n  \"DarkTheme\": \"Tema escuro\",\n  \"Delete\": \"Eliminar\",\n  \"DiscardChanges\": \"Descartar alterações\",\n  \"Disk\": \"Disco\",\n  \"Donate\": \"Doar\",\n  \"DownloadFFmpeg\": \"Descarregar o FFmpeg\",\n  \"Edit\": \"Editar\",\n  \"Elapsed\": \"Decorrido\",\n  \"ErrorOccurred\": \"Ocorreu um erro\",\n  \"Exit\": \"Sair\",\n  \"FFmpegFolder\": \"Pasta do FFmpeg\",\n  \"FFmpegLog\": \"Registo do FFmpeg\",\n  \"FileMenu\": \"Ficheiro\",\n  \"FileMenuNew\": \"Novo\",\n  \"FileMenuOpen\": \"Abrir\",\n  \"FileMenuSave\": \"Guardar\",\n  \"FileNaming\": \"Nomes de ficheiros\",\n  \"FontSize\": \"Tamanho da fonte\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Ecrã completo\",\n  \"HideOnFullScreenShot\": \"Ocultar na captura em ecrã completo\",\n  \"Host\": \"Servidor\",\n  \"Hotkeys\": \"Teclas de atalho\",\n  \"ImageEditor\": \"Editor de imagem\",\n  \"ImgEmpty\": \"Não guardado: a imagem capturada estava vazia\",\n  \"ImgFormat\": \"Formato de imagem\",\n  \"ImgSavedClipboard\": \"Imagem guardada na área de transferência\",\n  \"ImageUploadFailed\": \"Falha ao carregar a imagem\",\n  \"ImageUploadSuccess\": \"Carregamento da imagem com sucesso\",\n  \"ImageUploading\": \"A carregar imagem\",\n  \"IncludeClicks\": \"Incluir cliques do rato\",\n  \"IncludeCursor\": \"Incluir cursor\",\n  \"IncludeKeys\": \"Incluir toques em teclas\",\n  \"Keymap\": \"Mapa de teclas\",\n  \"Keystrokes\": \"Toques em teclas\",\n  \"KeystrokesHistoryCount\": \"Contagem de histórico\",\n  \"KeystrokesHistorySpacing\": \"Espaçamento de histórico\",\n  \"KeystrokesSeparateFile\": \"Guardar em ficheiro de texto adicional\",\n  \"Language\": \"Idioma\",\n  \"Left\": \"Esquerda\",\n  \"LoopbackSource\": \"Fonte de saída das colunas\",\n  \"MaxRecent\": \"Máximo de itens a manter\",\n  \"MaxTextLength\": \"Comprimento máximo do texto\",\n  \"MicSource\": \"Fonte do microfone\",\n  \"Minimize\": \"Minimizar\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Minimizar na área de notificação\",\n  \"MinTrayStartup\": \"Minimizar na área de notificação ao iniciar\",\n  \"MinTrayClose\": \"Minimizar na área de notificação ao fechar\",\n  \"MouseClicks\": \"Cliques do rato\",\n  \"MouseMiddleClickColor\": \"Cor do clique central\",\n  \"MousePointer\": \"Ponteiro do rato\",\n  \"MouseRightClickColor\": \"Cor do clique direito\",\n  \"NewWindow\": \"Nova janela\",\n  \"No\": \"Não\",\n  \"None\": \"Nenhum\",\n  \"Notifications\": \"Notificações\",\n  \"NotSaved\": \"Não guardado\",\n  \"NoWebcam\": \"Sem Webcam\",\n  \"Ok\": \"Aceitar\",\n  \"OnlyAudio\": \"Apenas áudio\",\n  \"Opacity\": \"Opacidade\",\n  \"OpenFromClipboard\": \"Abrir da área de transferência\",\n  \"OpenOutFolder\": \"Abrir pasta de saída\",\n  \"OutFolder\": \"Pasta de saída\",\n  \"Overlays\": \"Sobreposições\",\n  \"Padding\": \"Espaçamento\",\n  \"Password\": \"Senha\",\n  \"Paused\": \"Gravação em pausa\",\n  \"PauseResume\": \"Pausa | Retomar\",\n  \"PauseResumeRecording\": \"Pausa/Continuar gravação\",\n  \"Port\": \"Porta\",\n  \"Preview\": \"Pré-visualização\",\n  \"PreStartCountdown\": \"Pré-iniciar contagem regressiva (segundos)\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Qualidade\",\n  \"Radius\": \"Raio\",\n  \"Recent\": \"Recente\",\n  \"RecordStop\": \"Gravar | Parar\",\n  \"Redo\": \"Refazer\",\n  \"Refresh\": \"Atualizar\",\n  \"Region\": \"Região\",\n  \"RegionSelector\": \"Seletor de região\",\n  \"RemoveFromList\": \"Remover da lista\",\n  \"Reset\": \"Redefinir\",\n  \"Resize\": \"Redimensionar\",\n  \"RestoreDefaults\": \"Restaurar padrões\",\n  \"Right\": \"Direita\",\n  \"SaveToClipboard\": \"Copiar para área de transferência\",\n  \"Screen\": \"Ecrã\",\n  \"ScreenShot\": \"Captura de ecrã\",\n  \"ScreenShotActiveWindow\": \"Capturar janela ativa\",\n  \"ScreenShotDesktop\": \"Capturar área de trabalho\",\n  \"ScreenShotSaved\": \"Captura guardada\",\n  \"SelectFFmpegFolder\": \"Selecionar pasta do FFmpeg\",\n  \"SelectOutFolder\": \"Selecionar pasta de saída\",\n  \"SeparateAudioFiles\": \"Separar ficheiro por cada fonte de áudio\",\n  \"ShowSysNotify\": \"Exibir notificações na área de notificação\",\n  \"SnapToWindow\": \"Ajustar à janela\",\n  \"Sounds\": \"Sons\",\n  \"StartStopRecording\": \"Iniciar/Parar gravação\",\n  \"StreamingKeys\": \"Chaves de transmissão\",\n  \"Timeout\": \"Tempo limite\",\n  \"ToggleMouseClicks\": \"Alternar cliques do rato\",\n  \"ToggleKeystrokes\": \"Alternar toques em teclas\",\n  \"Tools\": \"Ferramentas\",\n  \"Top\": \"Topo\",\n  \"TrayIcon\": \"Ícone da área de notificação\",\n  \"Trim\": \"Aparar\",\n  \"Undo\": \"Desfazer\",\n  \"UploadToImgur\": \"Carregar para Imgur\",\n  \"UseProxyAuth\": \"Usar autenticação de Proxy\",\n  \"UserName\": \"Nome de utilizador\",\n  \"VarFrameRate\": \"Taxa de quadros variável\",\n  \"Video\": \"Vídeo\",\n  \"VideoEncoder\": \"Codificador de vídeo\",\n  \"VideoSaved\": \"Vídeo guardado\",\n  \"VideoSource\": \"Fonte de vídeo\",\n  \"ViewCrashLogs\": \"Ver registo de incidentes\",\n  \"ViewLicenses\": \"Ver licenças\",\n  \"ViewOnGitHub\": \"Ver no GitHub\",\n  \"WantToTranslate\": \"Quer ajudar a traduzir?\",\n  \"WebCam\": \"Webcam\",\n  \"WebCamSeparateFile\": \"Gravar Webcam em ficheiro separado\",\n  \"WebCamView\": \"Visualização da Webcam\",\n  \"Website\": \"Sítio Web\",\n  \"Window\": \"Janela\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Sim\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/ro.json",
    "content": "{\n  \"About\": \"Despre\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"Întotdeauna deasupra\",\n  \"Audio\": \"\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Audio salvat\",\n  \"BackColor\": \"Culoarea de pe fundal\",\n  \"BorderColor\": \"Culoarea marginii\",\n  \"BorderThickness\": \"Grosimea marginii\",\n  \"Bottom\": \"Jos\",\n  \"CaptureDuration\": \"Durata capturii (în secunde)\",\n  \"Center\": \"Centru\",\n  \"Changelog\": \"\",\n  \"Clear\": \"Șterge\",\n  \"ClearRecentList\": \"Șterge lista recentă\",\n  \"Clipboard\": \"\",\n  \"Close\": \"Închide\",\n  \"Color\": \"Culoare\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Configurare\",\n  \"CopyOutPathClipboard\": \"Copizază calea fișierului output în clipboard\",\n  \"CopyPath\": \"Copiaza cale\",\n  \"CopyToClipboard\": \"Copiază în clipboard\",\n  \"CornerRadius\": \"Raza colțurilor\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Șterge\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"Disc\",\n  \"Donate\": \"Donaează\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"A apărut o eroare\",\n  \"Exit\": \"Ieșire\",\n  \"FFmpegFolder\": \"\",\n  \"FFmpegLog\": \"\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Dimensiunea fontului\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"\",\n  \"HideOnFullScreenShot\": \"Ascunde în Screenshot al ecranului complet\",\n  \"Host\": \"\",\n  \"Hotkeys\": \"\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Nu a fost salvat. Imaginea a fost goală.\",\n  \"ImgFormat\": \"Formatul imaginii\",\n  \"ImgSavedClipboard\": \"Imagine salvată în Clipboard\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Include clicuri\",\n  \"IncludeCursor\": \"Include cursor\",\n  \"IncludeKeys\": \"Include keystrokes\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Limbă\",\n  \"Left\": \"Stânga\",\n  \"LoopbackSource\": \"Sursă de ieșire pentru difuzor\",\n  \"MaxRecent\": \"Număr maxim de elemente\",\n  \"MaxTextLength\": \"Lungimea maximă a textului\",\n  \"MicSource\": \"Sursă microfon\",\n  \"Minimize\": \"Minimizează\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Minimizează în System Tray\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Nu\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"Nu a fost salvat\",\n  \"NoWebcam\": \"Fără Webcam\",\n  \"Ok\": \"\",\n  \"OnlyAudio\": \"Doar Audio\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"Deschide folderul de ieșire\",\n  \"OutFolder\": \"Folder de ieșire\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Parolă\",\n  \"Paused\": \"Înregistrare întreruptă\",\n  \"PauseResume\": \"Pauză | Reia\",\n  \"PauseResumeRecording\": \"Întrerupe/Continuă înregistrarea\",\n  \"Port\": \"\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"\",\n  \"Quality\": \"Calitate\",\n  \"Radius\": \"Raza\",\n  \"Recent\": \"\",\n  \"RecordStop\": \"Înregistrează | Oprește\",\n  \"Redo\": \"\",\n  \"Refresh\": \"\",\n  \"Region\": \"Regiune\",\n  \"RegionSelector\": \"Selecția regiunii\",\n  \"RemoveFromList\": \"Șterge din listă\",\n  \"Reset\": \"Resetează\",\n  \"Resize\": \"Redimensionează\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Dreapta\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Ecran\",\n  \"ScreenShot\": \"Captură de ecran\",\n  \"ScreenShotActiveWindow\": \"Screenshot fereastra activă\",\n  \"ScreenShotDesktop\": \"Screenshot Desktop\",\n  \"ScreenShotSaved\": \"Screenshot salvat\",\n  \"SelectFFmpegFolder\": \"Selectează folderul FFmpeg\",\n  \"SelectOutFolder\": \"Selectează folder output\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Afișează notificările din System Tray\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Pornește/Oprește înregistrarea\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"Deasupra\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Folosește autentificare cu Proxy\",\n  \"UserName\": \"Nume utilizator\",\n  \"VarFrameRate\": \"Frame Rate variabil\",\n  \"Video\": \"\",\n  \"VideoEncoder\": \"Video encoder\",\n  \"VideoSaved\": \"Video salvat\",\n  \"VideoSource\": \"Sursă video\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Vrei să traduci?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"\",\n  \"Website\": \"\",\n  \"Window\": \"\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Da\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/ru.json",
    "content": "{\n  \"About\": \"О программе\",\n  \"AccentColor\": \"Цвет элементов\",\n  \"Add\": \"Добавить\",\n  \"AlwaysOnTop\": \"Поверх всех окон\",\n  \"Audio\": \"Звук\",\n  \"AudioFormat\": \"Формат аудио файла\",\n  \"AudioSaved\": \"Аудио файл сохранен\",\n  \"BackColor\": \"Цвет заднего фона\",\n  \"BorderColor\": \"Цвет границы\",\n  \"BorderThickness\": \"Толщина границы\",\n  \"Bottom\": \"Снизу\",\n  \"CaptureDuration\": \"Длительность захвата (в секундах)\",\n  \"Center\": \"По центру\",\n  \"Changelog\": \"История изменений\",\n  \"Clear\": \"Очистить\",\n  \"ClearRecentList\": \"Очистить список\",\n  \"Clipboard\": \"Буфер обмена\",\n  \"Close\": \"Закрыть\",\n  \"Color\": \"Цвет\",\n  \"ConfigCodecs\": \"Настройка кодеков\",\n  \"Configure\": \"Настройки\",\n  \"CopyOutPathClipboard\": \"Копировать путь к файлу в буфер обмена\",\n  \"CopyPath\": \"Копировать путь\",\n  \"CopyToClipboard\": \"Скопировать в буфер обмена\",\n  \"CornerRadius\": \"Радиус углов\",\n  \"CrashLogs\": \"Журнал ошибок\",\n  \"Crop\": \"Кадрировать\",\n  \"CustomSize\": \"Пользовательский размер\",\n  \"CustomUrl\": \"Другой ресурс\",\n  \"DarkTheme\": \"Темная тема\",\n  \"Delete\": \"Удалить\",\n  \"DiscardChanges\": \"Отменить изменения\",\n  \"Disk\": \"Диск\",\n  \"Donate\": \"Пожертвовать\",\n  \"DownloadFFmpeg\": \"Скачать FFmpeg\",\n  \"Edit\": \"Редактировать\",\n  \"Elapsed\": \"Показывать таймер\",\n  \"ErrorOccurred\": \"Произошла ошибка\",\n  \"Exit\": \"Выход\",\n  \"FFmpegFolder\": \"Папка FFmpeg\",\n  \"FFmpegLog\": \"Журнал FFmpeg\",\n  \"FileMenu\": \"Файл\",\n  \"FileMenuNew\": \"Новый\",\n  \"FileMenuOpen\": \"Открыть\",\n  \"FileMenuSave\": \"Сохранить\",\n  \"FileNaming\": \"Имя файла\",\n  \"FontSize\": \"Размер шрифта\",\n  \"FrameRate\": \"Кадров в секунду, FPS\",\n  \"FullScreen\": \"Весь экран\",\n  \"HideOnFullScreenShot\": \"Скрывать в полноэкранном режиме\",\n  \"Host\": \"Хост\",\n  \"Hotkeys\": \"Горячие клавиши\",\n  \"ImageEditor\": \"Редактор изображений\",\n  \"ImgEmpty\": \"Не сохранено. Получилось пустое изображение\",\n  \"ImgFormat\": \"Формат изображения\",\n  \"ImgSavedClipboard\": \"Изображение сохранено в буфер обмена\",\n  \"ImageUploadFailed\": \"Ошибка загрузки изображения\",\n  \"ImageUploadSuccess\": \"Загрузка изображения прошла успешно\",\n  \"ImageUploading\": \"Загрузка изображения\",\n  \"IncludeClicks\": \"Показывать щелчки мыши\",\n  \"IncludeCursor\": \"Показывать курсор\",\n  \"IncludeKeys\": \"Показывать нажатия клавиш\",\n  \"Keymap\": \"Раскладка\",\n  \"Keystrokes\": \"Нажатия клавиш\",\n  \"KeystrokesHistoryCount\": \"История нажатий\",\n  \"KeystrokesHistorySpacing\": \"Интервал истории\",\n  \"KeystrokesSeparateFile\": \"Сохранить в отдельный текстовый файл\",\n  \"Language\": \"Язык\",\n  \"Left\": \"Слева\",\n  \"LoopbackSource\": \"Источник воспроизведения звука\",\n  \"MaxRecent\": \"Количество записей\",\n  \"MaxTextLength\": \"Длина текста\",\n  \"MicSource\": \"Источник записи звука\",\n  \"Minimize\": \"Свернуть\",\n  \"MinToTrayOnCaptureStart\": \"Свернуть в трей перед началом записи\",\n  \"MinTray\": \"Свернуть в трей\",\n  \"MinTrayStartup\": \"Свернуть в трей при запуске программы\",\n  \"MinTrayClose\": \"Свернуть в трей при закрытии программы\",\n  \"MouseClicks\": \"Щелчки мыши\",\n  \"MouseMiddleClickColor\": \"Цвет средний кнопки мыши\",\n  \"MousePointer\": \"Указатель мыши\",\n  \"MouseRightClickColor\": \"Цвет правой кнопки мыши\",\n  \"NewWindow\": \"Новое окно\",\n  \"No\": \"Нет\",\n  \"None\": \"Ничего\",\n  \"Notifications\": \"Уведомления\",\n  \"NotSaved\": \"Не сохранено\",\n  \"NoWebcam\": \"Нет веб-камеры\",\n  \"Ok\": \"OK\",\n  \"OnlyAudio\": \"Только звук\",\n  \"Opacity\": \"Непрозрачность\",\n  \"OpenFromClipboard\": \"Открыть из буфера обмена\",\n  \"OpenOutFolder\": \"Открыть папку сохранения\",\n  \"OutFolder\": \"Папка сохранения\",\n  \"Overlays\": \"Оверлей\",\n  \"Padding\": \"Отступ\",\n  \"Password\": \"Пароль\",\n  \"Paused\": \"Запись приостановлена\",\n  \"PauseResume\": \"Приостановить запись | Продолжить запись\",\n  \"PauseResumeRecording\": \"Приостановить / Продолжить запись\",\n  \"Port\": \"Порт\",\n  \"Preview\": \"Предпросмотр\",\n  \"PreStartCountdown\": \"Отсчет времени до старта (в секундах)\",\n  \"Proxy\": \"Прокси\",\n  \"Quality\": \"Качество\",\n  \"Radius\": \"Радиус\",\n  \"Recent\": \"Последние действия\",\n  \"RecordStop\": \"Начать запись | Остановить запись\",\n  \"Redo\": \"Повторить\",\n  \"Refresh\": \"Обновить\",\n  \"Region\": \"Область экрана\",\n  \"RegionSelector\": \"Выбор области экрана\",\n  \"RemoveFromList\": \"Удалить из списка\",\n  \"Reset\": \"Очистить\",\n  \"Resize\": \"Изменить размер\",\n  \"RestoreDefaults\": \"Сбросить настройки\",\n  \"Right\": \"Справа\",\n  \"SaveToClipboard\": \"Сохранить в буфер обмена\",\n  \"Screen\": \"Экран\",\n  \"ScreenShot\": \"Снимок экрана\",\n  \"ScreenShotActiveWindow\": \"Снимок активного окна\",\n  \"ScreenShotDesktop\": \"Снимок рабочего стола\",\n  \"ScreenShotSaved\": \"Снимок сохранен\",\n  \"SelectFFmpegFolder\": \"Указать расположение FFmpeg\",\n  \"SelectOutFolder\": \"Выбрать папку сохранения\",\n  \"SeparateAudioFiles\": \"Записывать отдельный файл для каждого источника звука\",\n  \"ShowSysNotify\": \"Показывать уведомления в трее\",\n  \"SnapToWindow\": \"Указать привязку к окну\",\n  \"Sounds\": \"Звуки\",\n  \"StartStopRecording\": \"Начать / Остановить запись\",\n  \"StreamingKeys\": \"Настройки трансляции\",\n  \"Timeout\": \"Время ожидания\",\n  \"ToggleMouseClicks\": \"Показать щелчки мыши\",\n  \"ToggleKeystrokes\": \"Показать нажатие клавиш\",\n  \"Tools\": \"Инструменты\",\n  \"Top\": \"Сверху\",\n  \"TrayIcon\": \"Значок трея\",\n  \"Trim\": \"Обрезать видео\",\n  \"Undo\": \"Отменить\",\n  \"UploadToImgur\": \"Отправить на Imgur\",\n  \"UseProxyAuth\": \"Учетная запись прокси\",\n  \"UserName\": \"Имя пользователя\",\n  \"VarFrameRate\": \"Переменная частота кадров\",\n  \"Video\": \"Видео\",\n  \"VideoEncoder\": \"Видеокодек\",\n  \"VideoSaved\": \"Видео сохранено\",\n  \"VideoSource\": \"Источник видео\",\n  \"ViewCrashLogs\": \"Показать журнал ошибок\",\n  \"ViewLicenses\": \"Показать лицензии\",\n  \"ViewOnGitHub\": \"Показать на GitHub\",\n  \"WantToTranslate\": \"Хотите перевести?\",\n  \"WebCam\": \"Веб-камера\",\n  \"WebCamSeparateFile\": \"Запись с веб-камеры в отдельный файл\",\n  \"WebCamView\": \"Вид веб-камеры\",\n  \"Website\": \"Сайт программы\",\n  \"Window\": \"Окно\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Да\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/sl.json",
    "content": "{\n  \"About\": \"O programu\",\n  \"AccentColor\": \"Barva poudarka\",\n  \"Add\": \"Dodaj\",\n  \"AlwaysOnTop\": \"Vedno na vrhu\",\n  \"Audio\": \"Avdio\",\n  \"AudioFormat\": \"Avdio format\",\n  \"AudioSaved\": \"Zvočni posnetek shranjen\",\n  \"BackColor\": \"Barva ozadja\",\n  \"BorderColor\": \"Barva okvirja\",\n  \"BorderThickness\": \"Debelina okvirja\",\n  \"Bottom\": \"Dno\",\n  \"CaptureDuration\": \"Dolžina zajema (v sekundah)\",\n  \"Center\": \"Centralno\",\n  \"Changelog\": \"Zgodovina sprememb\",\n  \"Clear\": \"Počisti\",\n  \"ClearRecentList\": \"Počisti nedavne elemente\",\n  \"Clipboard\": \"Odložišče\",\n  \"Close\": \"Zapri\",\n  \"Color\": \"Barva\",\n  \"ConfigCodecs\": \"Nastavitve kodekov\",\n  \"Configure\": \"Prilagodi\",\n  \"CopyOutPathClipboard\": \"Kopiraj pot do datoteke v odložišče\",\n  \"CopyPath\": \"Kopiraj pot\",\n  \"CopyToClipboard\": \"Kopiraj v odložišče\",\n  \"CornerRadius\": \"Kotni radij\",\n  \"CrashLogs\": \"Zgodovina težav\",\n  \"Crop\": \"Obreži\",\n  \"CustomSize\": \"Velikost po meri\",\n  \"CustomUrl\": \"Url po meri\",\n  \"DarkTheme\": \"Temna tema vmesnika\",\n  \"Delete\": \"Izbriši\",\n  \"DiscardChanges\": \"Zavrzi spremembe\",\n  \"Disk\": \"Disk\",\n  \"Donate\": \"Podpri avtorja\",\n  \"DownloadFFmpeg\": \"Prenesi FFmpeg\",\n  \"Edit\": \"Uredi\",\n  \"Elapsed\": \"Preteklo\",\n  \"ErrorOccurred\": \"Prišlo je do napake\",\n  \"Exit\": \"Izhod\",\n  \"FFmpegFolder\": \"Lokacija FFmpeg\",\n  \"FFmpegLog\": \"FFmpeg log\",\n  \"FileMenu\": \"Datoteka\",\n  \"FileMenuNew\": \"Novo\",\n  \"FileMenuOpen\": \"Odpri\",\n  \"FileMenuSave\": \"Shrani\",\n  \"FileNaming\": \"Poimenovanje datotek\",\n  \"FontSize\": \"Velikost pisave\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Celoten zaslon\",\n  \"HideOnFullScreenShot\": \"Skrij pri celozaslonskem posnetku\",\n  \"Host\": \"Gostiteljski računalnik\",\n  \"Hotkeys\": \"Bližnjice\",\n  \"ImageEditor\": \"Urejevalnik slik\",\n  \"ImgEmpty\": \"Zajem ni uspel.\",\n  \"ImgFormat\": \"Format slike\",\n  \"ImgSavedClipboard\": \"Posnetek shranjen na odložišče\",\n  \"ImageUploadFailed\": \"Nalaganje slike ni uspelo\",\n  \"ImageUploadSuccess\": \"Nalaganje slike je uspelo\",\n  \"ImageUploading\": \"Nalaganje slike\",\n  \"IncludeClicks\": \"Vključno z miškinimi kliki\",\n  \"IncludeCursor\": \"Vključno z kurzorjem miške\",\n  \"IncludeKeys\": \"Zajemi tipkanje\",\n  \"Keymap\": \"Mapiranje tipk\",\n  \"Keystrokes\": \"Tipkanje\",\n  \"KeystrokesHistoryCount\": \"Število zapisov v zgodovini\",\n  \"KeystrokesHistorySpacing\": \"Razmik zgodovine\",\n  \"KeystrokesSeparateFile\": \"Shranite v ločeno besedilno datoteko\",\n  \"Language\": \"Jezik\",\n  \"Left\": \"Levo\",\n  \"LoopbackSource\": \"Zvočni izhod\",\n  \"MaxRecent\": \"Največ dovoljenih elementov\",\n  \"MaxTextLength\": \"Največja dovoljena dolžina teksta\",\n  \"MicSource\": \"Zvočni vhod\",\n  \"Minimize\": \"Pomanjšaj\",\n  \"MinToTrayOnCaptureStart\": \"Ob pričetku snemanja pomanjšaj v opravilno vrstico\",\n  \"MinTray\": \"Pomanjšaj v opravilno vrstico\",\n  \"MinTrayStartup\": \"Minimiziraj v opravilno vrstico ob zagonu\",\n  \"MinTrayClose\": \"Minimiziraj v opravilno vrstico ob zaprtju\",\n  \"MouseClicks\": \"Kliki miške\",\n  \"MouseMiddleClickColor\": \"Barva srednjega klika\",\n  \"MousePointer\": \"Miškin kazalec\",\n  \"MouseRightClickColor\": \"Barva desnega klika\",\n  \"NewWindow\": \"Novo okno\",\n  \"No\": \"Ne\",\n  \"None\": \"Noben\",\n  \"Notifications\": \"Obvestila\",\n  \"NotSaved\": \"Ni shranjen\",\n  \"NoWebcam\": \"Brez spletne kamere\",\n  \"Ok\": \"V redu\",\n  \"OnlyAudio\": \"Samo zvok\",\n  \"Opacity\": \"Prosojnost\",\n  \"OpenFromClipboard\": \"Odpri iz odložišča\",\n  \"OpenOutFolder\": \"Odpri mapo za shranjevanje\",\n  \"OutFolder\": \"Mapa za shranjevanje\",\n  \"Overlays\": \"Prekrivanje\",\n  \"Padding\": \"Odmik\",\n  \"Password\": \"Geslo\",\n  \"Paused\": \"Snemanje začasno zaustavljeno\",\n  \"PauseResume\": \"Začasno zaustavi | nadaljuj\",\n  \"PauseResumeRecording\": \"Začasno zaustavi / nadaljuj snemanje\",\n  \"Port\": \"Vrata (port)\",\n  \"Preview\": \"Predogled\",\n  \"PreStartCountdown\": \"Odštevalnik pred začetkom (v sekundah)\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Kvaliteta\",\n  \"Radius\": \"Radij\",\n  \"Recent\": \"Nedavno\",\n  \"RecordStop\": \"Snemaj | Zaustavi\",\n  \"Redo\": \"Ponovi\",\n  \"Refresh\": \"Osveži\",\n  \"Region\": \"Območje\",\n  \"RegionSelector\": \"Izbira območja\",\n  \"RemoveFromList\": \"Odstrani s sseznama\",\n  \"Reset\": \"Ponastavi\",\n  \"Resize\": \"Spremeni velikost\",\n  \"RestoreDefaults\": \"Obnovi privzeto\",\n  \"Right\": \"Desno\",\n  \"SaveToClipboard\": \"Kopiraj v odložišče\",\n  \"Screen\": \"Zaslon\",\n  \"ScreenShot\": \"Posnetek zaslona\",\n  \"ScreenShotActiveWindow\": \"Zajemite posnetek aktivnega okna\",\n  \"ScreenShotDesktop\": \"Zajemite posnetek namizja\",\n  \"ScreenShotSaved\": \"Posnetek zaslona je shranjen\",\n  \"SelectFFmpegFolder\": \"Izberi mapo kjer se nahaja FFmpeg\",\n  \"SelectOutFolder\": \"Izberite mapo za shranjevanje\",\n  \"SeparateAudioFiles\": \"Ločene datoteke za vsak zvočni vir\",\n  \"ShowSysNotify\": \"Prikaži opozorila v opravilni vrstici\",\n  \"SnapToWindow\": \"Pripni na okno\",\n  \"Sounds\": \"Zvoki\",\n  \"StartStopRecording\": \"Začni / prekini snemanje\",\n  \"StreamingKeys\": \"Nastavitve za prenašanje v živo (streaming)\",\n  \"Timeout\": \"Pavza\",\n  \"ToggleMouseClicks\": \"Zajem klikov na gumbe miške\",\n  \"ToggleKeystrokes\": \"Zajem pritiskov tipk na tipkovnici\",\n  \"Tools\": \"Orodja\",\n  \"Top\": \"Vrh\",\n  \"TrayIcon\": \"Ikona v opravilni vrstici\",\n  \"Trim\": \"Obreži\",\n  \"Undo\": \"Razveljavi\",\n  \"UploadToImgur\": \"Naloži na Imgur\",\n  \"UseProxyAuth\": \"Uporabi overjanje proxya\",\n  \"UserName\": \"Uporabniško ime\",\n  \"VarFrameRate\": \"Spremenljiva hitrost sličic\",\n  \"Video\": \"Video\",\n  \"VideoEncoder\": \"Video kodirnik\",\n  \"VideoSaved\": \"Videoposnetek shranjen\",\n  \"VideoSource\": \"Vir videa\",\n  \"ViewCrashLogs\": \"Poglej poročila o sesutju\",\n  \"ViewLicenses\": \"Preveri licence\",\n  \"ViewOnGitHub\": \"Poglej na GitHub-u\",\n  \"WantToTranslate\": \"Pomagajte pri prevodu\",\n  \"WebCam\": \"Spletna kamera\",\n  \"WebCamSeparateFile\": \"Snemanje spletne kamere v ločeno datoteko\",\n  \"WebCamView\": \"Pogled spletne kamere\",\n  \"Website\": \"Spletna stran\",\n  \"Window\": \"Okno\",\n  \"WindowScreenShotTransparency\": \"Obdrži transparentnost ob zajemu posnetka zaslona\",\n  \"Yes\": \"Da\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/sv.json",
    "content": "{\n  \"About\": \"Om\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"Fönster Alltid Överst\",\n  \"Audio\": \"Ljud\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Ljudet Sparat\",\n  \"BackColor\": \"Bakgrundsfärg\",\n  \"BorderColor\": \"Kantfärg\",\n  \"BorderThickness\": \"Kanttjocklek\",\n  \"Bottom\": \"Botten\",\n  \"CaptureDuration\": \"Filma X Antal Sekunder(i S)\",\n  \"Center\": \"Mitten\",\n  \"Changelog\": \"\",\n  \"Clear\": \"Rensa\",\n  \"ClearRecentList\": \"Töm senast använda\",\n  \"Clipboard\": \"Urklipp\",\n  \"Close\": \"Avsluta\",\n  \"Color\": \"Färg\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Konfiguera\",\n  \"CopyOutPathClipboard\": \"Kopiera Sökvägen till Sparningsmappen\",\n  \"CopyPath\": \"Kopiera Sökväg\",\n  \"CopyToClipboard\": \"Kopiera\",\n  \"CornerRadius\": \"Kantavrundning\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Radera\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"Hårddisk\",\n  \"Donate\": \"Donera\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"Ett Fel Har Uppstått\",\n  \"Exit\": \"Avsluta\",\n  \"FFmpegFolder\": \"FFmpeg Mapp\",\n  \"FFmpegLog\": \"FFmpeg Logg\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Font Storlek\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"Fullskärm\",\n  \"HideOnFullScreenShot\": \"Göm Vid Fullskärms Skärmbild\",\n  \"Host\": \"\",\n  \"Hotkeys\": \"Kortkommandon\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Inget Sparat. Bilden Var Tom\",\n  \"ImgFormat\": \"Bildformat\",\n  \"ImgSavedClipboard\": \"Bilden Sparad till Urklipp\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Inkludera Musklick\",\n  \"IncludeCursor\": \"Inkludera Muspekare\",\n  \"IncludeKeys\": \"Inkludera Knapptryck\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"Knapptryck\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Språk\",\n  \"Left\": \"Vänster\",\n  \"LoopbackSource\": \"Uppspelningsenhet\",\n  \"MaxRecent\": \"Max Antal Filer\",\n  \"MaxTextLength\": \"Max Text Längd\",\n  \"MicSource\": \"Mikrofon Källa\",\n  \"Minimize\": \"Minimera\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Minimera Till Verktygsfältet\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"Musklick\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Nej\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"Inget Sparades\",\n  \"NoWebcam\": \"Ingen Webbkamera\",\n  \"Ok\": \"\",\n  \"OnlyAudio\": \"Endast Ljud\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"Öppna Mappen För Sparningar\",\n  \"OutFolder\": \"Sparas i\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Lösenord\",\n  \"Paused\": \"Inspelning Pausad\",\n  \"PauseResume\": \"Pausa | Fortsätt\",\n  \"PauseResumeRecording\": \"Pausa/Fortsätt Inspelning\",\n  \"Port\": \"\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"\",\n  \"Quality\": \"Kvalitet\",\n  \"Radius\": \"Radie\",\n  \"Recent\": \"Nyligen\",\n  \"RecordStop\": \"Spela In | Stopp\",\n  \"Redo\": \"\",\n  \"Refresh\": \"Uppdatera\",\n  \"Region\": \"\",\n  \"RegionSelector\": \"Välj Region\",\n  \"RemoveFromList\": \"Ta Bort Från Lista\",\n  \"Reset\": \"Återställ\",\n  \"Resize\": \"Ändra Storlek\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"Höger\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Bildskärm\",\n  \"ScreenShot\": \"Skärmbild\",\n  \"ScreenShotActiveWindow\": \"Skärmbild Aktivt Fönster\",\n  \"ScreenShotDesktop\": \"Skärmbild Skrivbord\",\n  \"ScreenShotSaved\": \"Skärmbild Sparad\",\n  \"SelectFFmpegFolder\": \"Välj FFmpeg Mapp\",\n  \"SelectOutFolder\": \"Välj Vart Filerna Sparas\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Visa Notifikationer\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"Starta/Stoppa Inspelning \",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"Topp\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Använd Proxy Autentisering\",\n  \"UserName\": \"Användarnamn\",\n  \"VarFrameRate\": \"Varierande Bildhastighet\",\n  \"Video\": \"\",\n  \"VideoEncoder\": \"\",\n  \"VideoSaved\": \"Video Sparades\",\n  \"VideoSource\": \"Video Källa\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Vill Du Översätta\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"WebCam Vy\",\n  \"Website\": \"\",\n  \"Window\": \"Fönster\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Ja\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/th.json",
    "content": "{\n  \"About\": \"เกี่ยวกับ\",\n  \"AccentColor\": \"\",\n  \"Add\": \"\",\n  \"AlwaysOnTop\": \"อยู่บนสุดเสมอ\",\n  \"Audio\": \"บันทึกเสียง\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"บันทึกเสียงเรียบร้อย\",\n  \"BackColor\": \"สีพื้นหลัง\",\n  \"BorderColor\": \"สีขอบ\",\n  \"BorderThickness\": \"ความหนาของขอบ\",\n  \"Bottom\": \"ล่าง\",\n  \"CaptureDuration\": \"ระยะเวลาในการบันทึก (เป็นวินาที)\",\n  \"Center\": \"กลาง\",\n  \"Changelog\": \"บันทึกการเปลี่ยนแปลง\",\n  \"Clear\": \"ล้างข้อมูล\",\n  \"ClearRecentList\": \"ล้างข้อมูลล่าสุด\",\n  \"Clipboard\": \"คลิปบอร์ด\",\n  \"Close\": \"ปิด\",\n  \"Color\": \"สี\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"ตั้งค่า\",\n  \"CopyOutPathClipboard\": \" คัดลอกที่อยู่ไฟล์ที่บันทึกไปยังคลิปบอร์ด\",\n  \"CopyPath\": \"คัดลอกที่อยู่ไฟล์\",\n  \"CopyToClipboard\": \"คัดลอกไปยังคลิปบอร์ด\",\n  \"CornerRadius\": \"รัศมีหัวมุม\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"ลบ\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"ดิสก์\",\n  \"Donate\": \"บริจาค\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"เกิดข้อผิดพลาด\",\n  \"Exit\": \"ออก\",\n  \"FFmpegFolder\": \"โฟลเดอร์ของ FFmpeg\",\n  \"FFmpegLog\": \"Log ของ FFmpeg\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"ขนาดตัวอักษร\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"เต็มหน้าจอ\",\n  \"HideOnFullScreenShot\": \"ซ่อนตอนบันทึกภาพเต็มหน้าจอ\",\n  \"Host\": \"โฮส\",\n  \"Hotkeys\": \"ปุ่มลัด\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"ไม่สามารถบันทึกได้ เนื่องจากรูปที่เซฟมาว่างเปล่า\",\n  \"ImgFormat\": \"ฟอร์แมตของรูป\",\n  \"ImgSavedClipboard\": \"บันทึกรูปเข้าคลิปบอร์ด\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"รวมการคลิกเมาส์ด้วย\",\n  \"IncludeCursor\": \"รวมเคอร์เซอร์ด้วย\",\n  \"IncludeKeys\": \"รวมการกดปุ่มด้วย\",\n  \"Keymap\": \"\",\n  \"Keystrokes\": \"การกดปุ่ม\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"ภาษา\",\n  \"Left\": \"ซ้าย\",\n  \"LoopbackSource\": \"ช่องทางการส่งออกเสียง\",\n  \"MaxRecent\": \"จำนวนไอเท็มที่เก็บมากสุด\",\n  \"MaxTextLength\": \"ความยาวตัวอักษรมากสุด\",\n  \"MicSource\": \"ช่องทางนำเข้าไมค์โครโฟน\",\n  \"Minimize\": \"ย่อหน้าต่าง\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"ย่อหน้าต่างไป System Tray\",\n  \"MinTrayStartup\": \"\",\n  \"MinTrayClose\": \"\",\n  \"MouseClicks\": \"เมาส์คลิก\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"ไม่\",\n  \"None\": \"\",\n  \"Notifications\": \"\",\n  \"NotSaved\": \"ไม่ได้บันทึก\",\n  \"NoWebcam\": \"ไม่มีเว็บแคม\",\n  \"Ok\": \"ตกลง\",\n  \"OnlyAudio\": \"เสียงอย่างเดียว\",\n  \"Opacity\": \"\",\n  \"OpenFromClipboard\": \"\",\n  \"OpenOutFolder\": \"เปิดโฟลเดอร์ข้อมูลส่งออก\",\n  \"OutFolder\": \"โฟลเดอร์ข้อมูลส่งออก\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"รหัสผ่าน\",\n  \"Paused\": \"หยุดบรรทึกชั่วคราว\",\n  \"PauseResume\": \"หยุดชั่วคราว | ทำต่อ\",\n  \"PauseResumeRecording\": \"หยุดชั่วคราว/ทำต่อ การบันทึก\",\n  \"Port\": \"พอร์ต\",\n  \"Preview\": \"\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"พร็อกซี่\",\n  \"Quality\": \"คุณภาพ\",\n  \"Radius\": \"รัศมี\",\n  \"Recent\": \"ล่าสุด\",\n  \"RecordStop\": \"บันทึก | หยุด\",\n  \"Redo\": \"\",\n  \"Refresh\": \"รีเฟรช\",\n  \"Region\": \"บริเวณ\",\n  \"RegionSelector\": \"เลือกบริเวณ\",\n  \"RemoveFromList\": \"ลบออกจากรายการ\",\n  \"Reset\": \"รีเซ็ต\",\n  \"Resize\": \"ย่อขนาด\",\n  \"RestoreDefaults\": \"\",\n  \"Right\": \"ขวา\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"หน้าจอ\",\n  \"ScreenShot\": \"ภาพถ่ายหน้าจอ\",\n  \"ScreenShotActiveWindow\": \"ถ่ายหน้าจอโปรแกรมที่ใช้อยู่\",\n  \"ScreenShotDesktop\": \"ถ่ายหน้าจอเดสก์ท็อป\",\n  \"ScreenShotSaved\": \"บันทึกถ่ายหน้าจอเรียบร้อย\",\n  \"SelectFFmpegFolder\": \"เลือกที่อยู่โฟลเดอร์ FFmpeg\",\n  \"SelectOutFolder\": \"เลือกที่อยู่ข้อมูลส่งออก\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"แสดงการแจ้งเตือนจาก System Tray\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"\",\n  \"StartStopRecording\": \"เริ่ม/หยุด การบันทึก\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"หมดเวลา\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"\",\n  \"Top\": \"บน\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"ใช้การยืนยันตัวผ่านพร็อกซี่\",\n  \"UserName\": \"ยูเซอร์เนม\",\n  \"VarFrameRate\": \"เฟรมเรตแบบปรับเปลี่ยนได้\",\n  \"Video\": \"วิดีโอ\",\n  \"VideoEncoder\": \"ตัวเข้ารหัสวิดีโอ\",\n  \"VideoSaved\": \"บันทึกวิดีโอเรียบร้อย\",\n  \"VideoSource\": \"ที่มาของวิดีโอ\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"อยากที่จะแปล?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"ดูเว็บแคม\",\n  \"Website\": \"\",\n  \"Window\": \"หน้าต่าง\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"ใช่\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/tr.json",
    "content": "{\n  \"About\": \"Hakkında\",\n  \"AccentColor\": \"Vurgu Rengi\",\n  \"Add\": \"Ekle\",\n  \"AlwaysOnTop\": \"Her zaman Üstte\",\n  \"Audio\": \"Ses\",\n  \"AudioFormat\": \"Ses Formatı\",\n  \"AudioSaved\": \"Ses Kaydedildi\",\n  \"BackColor\": \"Arka Renk\",\n  \"BorderColor\": \"Kenarlık Rengi\",\n  \"BorderThickness\": \"Kenar Kalınlığı\",\n  \"Bottom\": \"Alt\",\n  \"CaptureDuration\": \"Yakalama Süresi (saniye)\",\n  \"Center\": \"Merkez\",\n  \"Changelog\": \"Değişiklik Notları\",\n  \"Clear\": \"Temizle\",\n  \"ClearRecentList\": \"Son Kullanılanlar Listesini Temizle\",\n  \"Clipboard\": \"Pano\",\n  \"Close\": \"Kapat\",\n  \"Color\": \"Renk\",\n  \"ConfigCodecs\": \"Kodekleri Yapılandır\",\n  \"Configure\": \"Yapılandır\",\n  \"CopyOutPathClipboard\": \"Çıktı dosya yolunu Panoya Kopyala\",\n  \"CopyPath\": \"Yolu Kopyala\",\n  \"CopyToClipboard\": \"Panoya Kopyala\",\n  \"CornerRadius\": \"Köşe Yarçapı\",\n  \"CrashLogs\": \"Kilitlenme Günlükleri\",\n  \"Crop\": \"Kırp\",\n  \"CustomSize\": \"Özel Boyut\",\n  \"CustomUrl\": \"Özel Url\",\n  \"DarkTheme\": \"Koyu Tema\",\n  \"Delete\": \"Sil\",\n  \"DiscardChanges\": \"Değişiklikleri İptal Et\",\n  \"Disk\": \"Disk\",\n  \"Donate\": \"Bağış Yap\",\n  \"DownloadFFmpeg\": \"FFmpeg İndir\",\n  \"Edit\": \"Düzenle\",\n  \"Elapsed\": \"Geçen süre\",\n  \"ErrorOccurred\": \"Bir Hata Oluştu\",\n  \"Exit\": \"Çıkış\",\n  \"FFmpegFolder\": \"FFmpeg Klasörü\",\n  \"FFmpegLog\": \"FFmpeg Günlüğü\",\n  \"FileMenu\": \"Dosya\",\n  \"FileMenuNew\": \"Yeni\",\n  \"FileMenuOpen\": \"Aç\",\n  \"FileMenuSave\": \"Kaydet\",\n  \"FileNaming\": \"Dosya Adlandırma\",\n  \"FontSize\": \"Yazı Boyutu\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Tam Ekran\",\n  \"HideOnFullScreenShot\": \"Tam Ekran Görüntüsü Alındığında Gizle\",\n  \"Host\": \"Sunucu\",\n  \"Hotkeys\": \"Klavye kısayolları\",\n  \"ImageEditor\": \"Resim Editörü\",\n  \"ImgEmpty\": \"Kaydedilmedi. Alınan Görüntü Boş\",\n  \"ImgFormat\": \"Görüntü Formatı\",\n  \"ImgSavedClipboard\": \"Görüntü Panoya Kaydedildi\",\n  \"ImageUploadFailed\": \"Görüntü Yükleme Başarısız\",\n  \"ImageUploadSuccess\": \"Görüntü Yükleme Başarılı\",\n  \"ImageUploading\": \"Görüntü Yükleniyor\",\n  \"IncludeClicks\": \"Fare Tıklamalarını Ekle\",\n  \"IncludeCursor\": \"İmleci Ekle\",\n  \"IncludeKeys\": \"Tuş Vuruşlarını Ekle\",\n  \"Keymap\": \"Klavye düzeni\",\n  \"Keystrokes\": \"Tuş Vuruşları\",\n  \"KeystrokesHistoryCount\": \"Geçmiş Sayısı\",\n  \"KeystrokesHistorySpacing\": \"Geçmiş Aralığı\",\n  \"KeystrokesSeparateFile\": \"Ayrı metin dosyasına Kaydet\",\n  \"Language\": \"Dil\",\n  \"Left\": \"Sol\",\n  \"LoopbackSource\": \"Hoparlör Çıkış Kaynağı\",\n  \"MaxRecent\": \"Kalacak azami öge sayısı\",\n  \"MaxTextLength\": \"Azami Yazı Uzunluğu\",\n  \"MicSource\": \"Mikrofon Kaynağı\",\n  \"Minimize\": \"Küçült\",\n  \"MinToTrayOnCaptureStart\": \"Kayıt Başladığında Tepsiye Küçült\",\n  \"MinTray\": \"Sistem Tepsisine Küçült\",\n  \"MinTrayStartup\": \"Başlangıçta Sistem Tepsisine Küçült\",\n  \"MinTrayClose\": \"Kapatıldığında Sistem Tepsisine Küçült\",\n  \"MouseClicks\": \"Fare Tıklamaları\",\n  \"MouseMiddleClickColor\": \"Orta Tıklama Rengi\",\n  \"MousePointer\": \"Fare İmleci\",\n  \"MouseRightClickColor\": \"Sağ Tıklama Rengi\",\n  \"NewWindow\": \"Yeni Pencere\",\n  \"No\": \"Hayır\",\n  \"None\": \"Yok\",\n  \"Notifications\": \"Bildirimler\",\n  \"NotSaved\": \"Kaydedilmedi\",\n  \"NoWebcam\": \"Webcam Yok\",\n  \"Ok\": \"Tamam\",\n  \"OnlyAudio\": \"Yalnızca Ses\",\n  \"Opacity\": \"Opaklık\",\n  \"OpenFromClipboard\": \"Panodan Aç\",\n  \"OpenOutFolder\": \"Çıktı Klasörünü Aç\",\n  \"OutFolder\": \"Çıktı Klasörü\",\n  \"Overlays\": \"Üzerine Eklemeler\",\n  \"Padding\": \"Dolgu\",\n  \"Password\": \"Parola\",\n  \"Paused\": \"Kayıt Duraklatıldı\",\n  \"PauseResume\": \"Duraklat | Devam Et\",\n  \"PauseResumeRecording\": \"Kaydı Duraklat/Devam Et\",\n  \"Port\": \"Bağlantı noktası\",\n  \"Preview\": \"Önizle\",\n  \"PreStartCountdown\": \"Ön başlangıç geri sayım (saniye)\",\n  \"Proxy\": \"Vekil\",\n  \"Quality\": \"Kalite\",\n  \"Radius\": \"Yarıçap\",\n  \"Recent\": \"Son kullanılanlar\",\n  \"RecordStop\": \"Kaydet | Dur\",\n  \"Redo\": \"Yinele\",\n  \"Refresh\": \"Yenile\",\n  \"Region\": \"Bölge\",\n  \"RegionSelector\": \"Bölge Seçici\",\n  \"RemoveFromList\": \"Listeden Kaldır\",\n  \"Reset\": \"Sıfırla\",\n  \"Resize\": \"Yeniden boyutlandır\",\n  \"RestoreDefaults\": \"Varsayılanları Yükle\",\n  \"Right\": \"Sağ\",\n  \"SaveToClipboard\": \"Panoya Kaydet\",\n  \"Screen\": \"Ekran\",\n  \"ScreenShot\": \"Ekran Görüntüsü\",\n  \"ScreenShotActiveWindow\": \"Aktif Pencerenin Ekran Görüntüsü\",\n  \"ScreenShotDesktop\": \"Masaüstünün Ekran Görüntüsü\",\n  \"ScreenShotSaved\": \"Ekran Görüntüsü Kaydedildi\",\n  \"SelectFFmpegFolder\": \"FFmpeg Klasörünü Seç\",\n  \"SelectOutFolder\": \"Çıktı Klasörünü Seç\",\n  \"SeparateAudioFiles\": \"Her ses kaynağı için ayrı dosya\",\n  \"ShowSysNotify\": \"Sistem Tepsisi Bildirimlerini Göster\",\n  \"SnapToWindow\": \"Pencereyi yakala\",\n  \"Sounds\": \"Sesler\",\n  \"StartStopRecording\": \"Kaydı Başlat/Durdur\",\n  \"StreamingKeys\": \"Akış Anahtarları\",\n  \"Timeout\": \"Zaman Aşımı\",\n  \"ToggleMouseClicks\": \"Fare Tıklamalarını Değiştir\",\n  \"ToggleKeystrokes\": \"Tuş vuruşlarını değiştir\",\n  \"Tools\": \"Araçlar\",\n  \"Top\": \"Üst\",\n  \"TrayIcon\": \"Tepsi Simgesi\",\n  \"Trim\": \"Kırp\",\n  \"Undo\": \"Geri al\",\n  \"UploadToImgur\": \"Imgur'a Yükle\",\n  \"UseProxyAuth\": \"Vekil Kimlik Doğrulaması Kullan\",\n  \"UserName\": \"Kullanıcı Adı\",\n  \"VarFrameRate\": \"Değişken Kare Hızı\",\n  \"Video\": \"Video\",\n  \"VideoEncoder\": \"Video Kodlayıcı\",\n  \"VideoSaved\": \"Video Kaydedildi\",\n  \"VideoSource\": \"Video Kaynağı\",\n  \"ViewCrashLogs\": \"Kilitlenme Günlüklerini Göster\",\n  \"ViewLicenses\": \"Lisansları Göster\",\n  \"ViewOnGitHub\": \"GitHub'da Göster\",\n  \"WantToTranslate\": \"Tercüme etmek ister misin?\",\n  \"WebCam\": \"Web kamerası\",\n  \"WebCamSeparateFile\": \"Web kamerasını ayrı bir dosyaya kaydet\",\n  \"WebCamView\": \"Web Kamerası Görüntüsü\",\n  \"Website\": \"Web sitesi\",\n  \"Window\": \"Pencere\",\n  \"WindowScreenShotTransparency\": \"Ekran görüntüleri pencere modunda şeffaf olmalı\",\n  \"Yes\": \"Evet\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/uk.json",
    "content": "{\n  \"About\": \"Про програму\",\n  \"AccentColor\": \"\",\n  \"Add\": \"Добавити\",\n  \"AlwaysOnTop\": \"Завжди на передньому плані\",\n  \"Audio\": \"Звук\",\n  \"AudioFormat\": \"\",\n  \"AudioSaved\": \"Звук збережений\",\n  \"BackColor\": \"Колір фону\",\n  \"BorderColor\": \"Колір границі\",\n  \"BorderThickness\": \"Товщина границі\",\n  \"Bottom\": \"Знизу\",\n  \"CaptureDuration\": \"Час захоплення (в секундах)\",\n  \"Center\": \"По центру\",\n  \"Changelog\": \"Зміни\",\n  \"Clear\": \"Очистити\",\n  \"ClearRecentList\": \"Очистити список\",\n  \"Clipboard\": \"Буфер обміну\",\n  \"Close\": \"Закрити\",\n  \"Color\": \"Колір\",\n  \"ConfigCodecs\": \"\",\n  \"Configure\": \"Налаштування\",\n  \"CopyOutPathClipboard\": \"Скопіювати шлях до файлу в буфер обміну\",\n  \"CopyPath\": \"Шлях копіювання\",\n  \"CopyToClipboard\": \"Скопіювати в буфер обміну\",\n  \"CornerRadius\": \"Радіус кутів\",\n  \"CrashLogs\": \"\",\n  \"Crop\": \"\",\n  \"CustomSize\": \"\",\n  \"CustomUrl\": \"\",\n  \"DarkTheme\": \"\",\n  \"Delete\": \"Видалити\",\n  \"DiscardChanges\": \"\",\n  \"Disk\": \"Диск\",\n  \"Donate\": \"Пожертвувати\",\n  \"DownloadFFmpeg\": \"\",\n  \"Edit\": \"\",\n  \"Elapsed\": \"\",\n  \"ErrorOccurred\": \"Виникла помилка\",\n  \"Exit\": \"Вихід\",\n  \"FFmpegFolder\": \"Папка з FFmpeg\",\n  \"FFmpegLog\": \"Журнал FFmpeg\",\n  \"FileMenu\": \"\",\n  \"FileMenuNew\": \"\",\n  \"FileMenuOpen\": \"\",\n  \"FileMenuSave\": \"\",\n  \"FileNaming\": \"\",\n  \"FontSize\": \"Розмір шрифту\",\n  \"FrameRate\": \"\",\n  \"FullScreen\": \"Весь екран\",\n  \"HideOnFullScreenShot\": \"Приховувати в повноекранному режимі\",\n  \"Host\": \"Хост\",\n  \"Hotkeys\": \"Гарячі клавіші\",\n  \"ImageEditor\": \"\",\n  \"ImgEmpty\": \"Не збережено. Отримано пусте зображення\",\n  \"ImgFormat\": \"Формат зображення\",\n  \"ImgSavedClipboard\": \"Зображення збережено в буфер обміну\",\n  \"ImageUploadFailed\": \"\",\n  \"ImageUploadSuccess\": \"\",\n  \"ImageUploading\": \"\",\n  \"IncludeClicks\": \"Показувати кліки миші\",\n  \"IncludeCursor\": \"Показувати курсор\",\n  \"IncludeKeys\": \"Показувати натиснення клавіш\",\n  \"Keymap\": \"Розкладка\",\n  \"Keystrokes\": \"Натиснення клавіш\",\n  \"KeystrokesHistoryCount\": \"\",\n  \"KeystrokesHistorySpacing\": \"\",\n  \"KeystrokesSeparateFile\": \"\",\n  \"Language\": \"Мова\",\n  \"Left\": \"Зліва\",\n  \"LoopbackSource\": \"Пристрій відтворення звуку\",\n  \"MaxRecent\": \"К-сть елементів\",\n  \"MaxTextLength\": \"Довжина тексту\",\n  \"MicSource\": \"Джерело звуку\",\n  \"Minimize\": \"Згорнути\",\n  \"MinToTrayOnCaptureStart\": \"\",\n  \"MinTray\": \"Згорнути в трей\",\n  \"MinTrayStartup\": \"Згортати до системного лотка при запуску\",\n  \"MinTrayClose\": \"Мінімізувати до системного лотка при закритті\",\n  \"MouseClicks\": \"Кліки миші\",\n  \"MouseMiddleClickColor\": \"\",\n  \"MousePointer\": \"\",\n  \"MouseRightClickColor\": \"\",\n  \"NewWindow\": \"\",\n  \"No\": \"Ні\",\n  \"None\": \"Нічого\",\n  \"Notifications\": \"Сповіщення\",\n  \"NotSaved\": \"Не збережено\",\n  \"NoWebcam\": \"Немає веб-камери\",\n  \"Ok\": \"OK\",\n  \"OnlyAudio\": \"Тільки звук\",\n  \"Opacity\": \"Прозорість\",\n  \"OpenFromClipboard\": \"Імпортувати з буфера обміну\",\n  \"OpenOutFolder\": \"Відкрити папку збереження\",\n  \"OutFolder\": \"Папка збереження\",\n  \"Overlays\": \"\",\n  \"Padding\": \"\",\n  \"Password\": \"Пароль\",\n  \"Paused\": \"Запис призупинено\",\n  \"PauseResume\": \"Призупинити | Відновити\",\n  \"PauseResumeRecording\": \"Пауза/старт запису\",\n  \"Port\": \"Порт\",\n  \"Preview\": \"Попередній перегляд\",\n  \"PreStartCountdown\": \"\",\n  \"Proxy\": \"Проксі\",\n  \"Quality\": \"Якість\",\n  \"Radius\": \"Радіус\",\n  \"Recent\": \"Останнє\",\n  \"RecordStop\": \"Почати запис | Зупинити запис\",\n  \"Redo\": \"\",\n  \"Refresh\": \"Оновити\",\n  \"Region\": \"Область екрану\",\n  \"RegionSelector\": \"Вибір області захоплення\",\n  \"RemoveFromList\": \"Видалити зі списку\",\n  \"Reset\": \"Скидання\",\n  \"Resize\": \"Змінити розмір\",\n  \"RestoreDefaults\": \"За замовчуванням\",\n  \"Right\": \"Справа\",\n  \"SaveToClipboard\": \"\",\n  \"Screen\": \"Екран\",\n  \"ScreenShot\": \"Знімок екрану\",\n  \"ScreenShotActiveWindow\": \"Знімок активного вікна\",\n  \"ScreenShotDesktop\": \"Знімок робочого столу\",\n  \"ScreenShotSaved\": \"Знімок збережено\",\n  \"SelectFFmpegFolder\": \"Вказати папку\",\n  \"SelectOutFolder\": \"Виберіть папку збереження\",\n  \"SeparateAudioFiles\": \"\",\n  \"ShowSysNotify\": \"Показувати сповіщення в треї\",\n  \"SnapToWindow\": \"\",\n  \"Sounds\": \"Звуки\",\n  \"StartStopRecording\": \"Старт/стоп запису\",\n  \"StreamingKeys\": \"\",\n  \"Timeout\": \"Таймаут\",\n  \"ToggleMouseClicks\": \"\",\n  \"ToggleKeystrokes\": \"\",\n  \"Tools\": \"Інструменти\",\n  \"Top\": \"Зверху\",\n  \"TrayIcon\": \"\",\n  \"Trim\": \"\",\n  \"Undo\": \"\",\n  \"UploadToImgur\": \"\",\n  \"UseProxyAuth\": \"Обліковий запис проксі\",\n  \"UserName\": \"Ім'я користувача\",\n  \"VarFrameRate\": \"Змінна частота кадрів\",\n  \"Video\": \"Відео\",\n  \"VideoEncoder\": \"Відеокодек\",\n  \"VideoSaved\": \"Відео збережено\",\n  \"VideoSource\": \"Джерело відео\",\n  \"ViewCrashLogs\": \"\",\n  \"ViewLicenses\": \"\",\n  \"ViewOnGitHub\": \"\",\n  \"WantToTranslate\": \"Хочете перекласти?\",\n  \"WebCam\": \"\",\n  \"WebCamSeparateFile\": \"\",\n  \"WebCamView\": \"Вид веб-камери\",\n  \"Website\": \"\",\n  \"Window\": \"Вікно\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"Так\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/vi.json",
    "content": "{\n  \"About\": \"Giới thiệu\",\n  \"AccentColor\": \"Màu điểm nhấn\",\n  \"Add\": \"Thêm\",\n  \"AlwaysOnTop\": \"Hiện Captura trước tiên\",\n  \"Audio\": \"Âm thanh\",\n  \"AudioFormat\": \"Định dạng âm thanh\",\n  \"AudioSaved\": \"Đã lưu âm thanh\",\n  \"BackColor\": \"Màu nền\",\n  \"BorderColor\": \"Màu của cạnh\",\n  \"BorderThickness\": \"Độ dày của cạnh\",\n  \"Bottom\": \"Bên dưới\",\n  \"CaptureDuration\": \"Quay trong (giây)\",\n  \"Center\": \"Chính giữa\",\n  \"Changelog\": \"Thay đổi\",\n  \"Clear\": \"Xóa\",\n  \"ClearRecentList\": \"Xóa danh sách gần đây\",\n  \"Clipboard\": \"Clipboard\",\n  \"Close\": \"Đóng\",\n  \"Color\": \"Màu\",\n  \"ConfigCodecs\": \"Cấu hình Codecs\",\n  \"Configure\": \"Cài đặt\",\n  \"CopyOutPathClipboard\": \"Sao chép đường dẫn file video vào clipboard\",\n  \"CopyPath\": \"Sao chép đường dẫn\",\n  \"CopyToClipboard\": \"Sao chép vào Clipboard\",\n  \"CornerRadius\": \"Bo góc\",\n  \"CrashLogs\": \"Nhật ký sự cố\",\n  \"Crop\": \"Crop\",\n  \"CustomSize\": \"Kích thước tùy chỉnh\",\n  \"CustomUrl\": \"Url tùy chỉnh\",\n  \"DarkTheme\": \"Dark Theme\",\n  \"Delete\": \"Xóa\",\n  \"DiscardChanges\": \"Hủy thay đổi\",\n  \"Disk\": \"Ổ đĩa\",\n  \"Donate\": \"Donate\",\n  \"DownloadFFmpeg\": \"Cài đặt FFmpeg\",\n  \"Edit\": \"Chỉnh sửa\",\n  \"Elapsed\": \"Trôi qua\",\n  \"ErrorOccurred\": \"Một lỗi đã xảy ra\",\n  \"Exit\": \"Thoát\",\n  \"FFmpegFolder\": \"Thư mục FFmpeg\",\n  \"FFmpegLog\": \"Lịch sử FFmpeg\",\n  \"FileMenu\": \"File\",\n  \"FileMenuNew\": \"Mới\",\n  \"FileMenuOpen\": \"Mở\",\n  \"FileMenuSave\": \"Lưu\",\n  \"FileNaming\": \"Đặt tên File\",\n  \"FontSize\": \"Độ lớn của font\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"Toàn màn hình\",\n  \"HideOnFullScreenShot\": \"Ẩn Captura khi chụp ảnh màn hình\",\n  \"Host\": \"Máy chủ\",\n  \"Hotkeys\": \"Phím nóng\",\n  \"ImageEditor\": \"Trình chỉnh sửa ảnh\",\n  \"ImgEmpty\": \"Chưa lưu ảnh\",\n  \"ImgFormat\": \"Định dạng ảnh\",\n  \"ImgSavedClipboard\": \"Ảnh đã lưu vào clipboard\",\n  \"ImageUploadFailed\": \"Đăng ảnh thất bại\",\n  \"ImageUploadSuccess\": \"Đăng ảnh thành công\",\n  \"ImageUploading\": \"Đang đăng ảnh\",\n  \"IncludeClicks\": \"Làm nổi bật click chuột\",\n  \"IncludeCursor\": \"Làm nổi bật con trỏ chuột\",\n  \"IncludeKeys\": \"Làm nổi bật tổ hợp phím\",\n  \"Keymap\": \"Bố cục bàn phím\",\n  \"Keystrokes\": \"Tổ hợp phím\",\n  \"KeystrokesHistoryCount\": \"Số lượng phím tắt hiển thị tối đa\",\n  \"KeystrokesHistorySpacing\": \"Khoảng cách hiển thị phím tắt\",\n  \"KeystrokesSeparateFile\": \"Lưu vào file văn bản\",\n  \"Language\": \"Ngôn ngữ\",\n  \"Left\": \"Trái\",\n  \"LoopbackSource\": \"Nguồn loa\",\n  \"MaxRecent\": \"Số item hiện tối đa\",\n  \"MaxTextLength\": \"Chiều dài tối đa của text\",\n  \"MicSource\": \"Nguồn microphone\",\n  \"Minimize\": \"Thu nhỏ\",\n  \"MinToTrayOnCaptureStart\": \"Thu nhỏ khi bắt đầu quay\",\n  \"MinTray\": \"Thu nhỏ xuống taskbar\",\n  \"MinTrayStartup\": \"Thu nhỏ khi khởi động\",\n  \"MinTrayClose\": \"Thu nhỏ khi đóng\",\n  \"MouseClicks\": \"Click chuột\",\n  \"MouseMiddleClickColor\": \"Màu chuột giữa\",\n  \"MousePointer\": \"Con trỏ chuột\",\n  \"MouseRightClickColor\": \"Màu chuột phải\",\n  \"NewWindow\": \"Cửa sổ mới\",\n  \"No\": \"Không\",\n  \"None\": \"Trống\",\n  \"Notifications\": \"Thông báo\",\n  \"NotSaved\": \"Chưa lưu\",\n  \"NoWebcam\": \"Không webcam\",\n  \"Ok\": \"Đồng ý\",\n  \"OnlyAudio\": \"Chỉ ghi âm\",\n  \"Opacity\": \"Độ mờ\",\n  \"OpenFromClipboard\": \"Dán từ Clipboard\",\n  \"OpenOutFolder\": \"Mở folder lưu video\",\n  \"OutFolder\": \"Folder lưu video\",\n  \"Overlays\": \"Lớp phủ\",\n  \"Padding\": \"Khoảng cách\",\n  \"Password\": \"Mật khẩu\",\n  \"Paused\": \"Đã tạm dừng quay màn hình\",\n  \"PauseResume\": \"Tạm dừng | Tiếp tục\",\n  \"PauseResumeRecording\": \"Tạm dừng/Tiếp tục quay màn hình\",\n  \"Port\": \"Cổng\",\n  \"Preview\": \"Xem trước\",\n  \"PreStartCountdown\": \"Đếm ngược trước khi bắt đầu quay (giây)\",\n  \"Proxy\": \"Proxy\",\n  \"Quality\": \"Chất lượng\",\n  \"Radius\": \"Bán kính\",\n  \"Recent\": \"Gần đây\",\n  \"RecordStop\": \"Bắt đầu | Dừng lại\",\n  \"Redo\": \"Làm lại\",\n  \"Refresh\": \"Làm mới\",\n  \"Region\": \"Vùng\",\n  \"RegionSelector\": \"Quay một vùng trên màn hình\",\n  \"RemoveFromList\": \"Xóa khỏi danh sách\",\n  \"Reset\": \"Đặt lại\",\n  \"Resize\": \"Sửa kích thước\",\n  \"RestoreDefaults\": \"Khôi phục Cài đặt gốc\",\n  \"Right\": \"Phải\",\n  \"SaveToClipboard\": \"Sao chép vào Clipboard\",\n  \"Screen\": \"Màn hình\",\n  \"ScreenShot\": \"Chụp ảnh toàn màn hình\",\n  \"ScreenShotActiveWindow\": \"Chụp cửa số đang active\",\n  \"ScreenShotDesktop\": \"Chụp ảnh desktop\",\n  \"ScreenShotSaved\": \"Đã lưu ảnh chụp màn hình\",\n  \"SelectFFmpegFolder\": \"Chọn thư mục FFmpeg\",\n  \"SelectOutFolder\": \"Chọn folder lưu file\",\n  \"SeparateAudioFiles\": \"Tách âm thanh thành những file riêng biệt\",\n  \"ShowSysNotify\": \"Hiện thông báo trên taskbar\",\n  \"SnapToWindow\": \"Chụp ảnh cửa sổ\",\n  \"Sounds\": \"Âm thanh\",\n  \"StartStopRecording\": \"Bắt đầu/Dừng quay màn hình\",\n  \"StreamingKeys\": \"Stream key\",\n  \"Timeout\": \"Thời gian hiện\",\n  \"ToggleMouseClicks\": \"Làm nổi bật click chuột\",\n  \"ToggleKeystrokes\": \"Tổ hợp phím\",\n  \"Tools\": \"Công cụ\",\n  \"Top\": \"Bên trên\",\n  \"TrayIcon\": \"Biểu tượng trên thanh công cụ\",\n  \"Trim\": \"Cắt\",\n  \"Undo\": \"Hoàn tác\",\n  \"UploadToImgur\": \"Tải lên Imgur\",\n  \"UseProxyAuth\": \"Dùng phương thức xác thực Proxy\",\n  \"UserName\": \"Tên đăng nhập\",\n  \"VarFrameRate\": \"Chuẩn khung hình\",\n  \"Video\": \"Video\",\n  \"VideoEncoder\": \"Trình mã hóa video\",\n  \"VideoSaved\": \"Đã lưu video\",\n  \"VideoSource\": \"Đường dẫn tới video\",\n  \"ViewCrashLogs\": \"Xem nhật ký sự cố\",\n  \"ViewLicenses\": \"Xem bản quyền\",\n  \"ViewOnGitHub\": \"Xem trên GitHub\",\n  \"WantToTranslate\": \"Không có ngôn ngữ của bạn?\",\n  \"WebCam\": \"Webcam\",\n  \"WebCamSeparateFile\": \"Ghi Webcam vào file riêng biệt\",\n  \"WebCamView\": \"Xem WebCam\",\n  \"Website\": \"Trang chủ\",\n  \"Window\": \"Cửa sổ\",\n  \"WindowScreenShotTransparency\": \"Chụp cửa sổ ở chế độ Ảnh Trong suốt\",\n  \"Yes\": \"Đồng ý\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/zh-CN.json",
    "content": "{\n  \"About\": \"关于\",\n  \"AccentColor\": \"色调\",\n  \"Add\": \"添加\",\n  \"AlwaysOnTop\": \"窗口置顶\",\n  \"Audio\": \"音频\",\n  \"AudioFormat\": \"音频格式\",\n  \"AudioSaved\": \"音频已保存\",\n  \"BackColor\": \"背景色\",\n  \"BorderColor\": \"边框颜色\",\n  \"BorderThickness\": \"边框宽度\",\n  \"Bottom\": \"底部\",\n  \"CaptureDuration\": \"录制持续时间 (秒)\",\n  \"Center\": \"局中\",\n  \"Changelog\": \"更新日志\",\n  \"Clear\": \"清空\",\n  \"ClearRecentList\": \"清除近期录制列表\",\n  \"Clipboard\": \"剪贴板\",\n  \"Close\": \"关闭\",\n  \"Color\": \"颜色\",\n  \"ConfigCodecs\": \"配置编解码器\",\n  \"Configure\": \"配置\",\n  \"CopyOutPathClipboard\": \"复制输出文件路径至剪贴板\",\n  \"CopyPath\": \"复制路径\",\n  \"CopyToClipboard\": \"复制到剪贴板\",\n  \"CornerRadius\": \"圆角半径\",\n  \"CrashLogs\": \"崩溃日志\",\n  \"Crop\": \"裁剪\",\n  \"CustomSize\": \"自定义大小\",\n  \"CustomUrl\": \"自定义 URL\",\n  \"DarkTheme\": \"黑色主题\",\n  \"Delete\": \"删除\",\n  \"DiscardChanges\": \"放弃修改\",\n  \"Disk\": \"硬盘\",\n  \"Donate\": \"捐助\",\n  \"DownloadFFmpeg\": \"下载FFmpeg\",\n  \"Edit\": \"编辑\",\n  \"Elapsed\": \"已用\",\n  \"ErrorOccurred\": \"发生了一个错误\",\n  \"Exit\": \"退出\",\n  \"FFmpegFolder\": \"FFmpeg目录\",\n  \"FFmpegLog\": \"FFmpeg日志\",\n  \"FileMenu\": \"文件\",\n  \"FileMenuNew\": \"新建\",\n  \"FileMenuOpen\": \"打开\",\n  \"FileMenuSave\": \"保存\",\n  \"FileNaming\": \"文件命名\",\n  \"FontSize\": \"字体大小\",\n  \"FrameRate\": \"帧率\",\n  \"FullScreen\": \"全屏\",\n  \"HideOnFullScreenShot\": \"全屏截图时隐藏\",\n  \"Host\": \"主机\",\n  \"Hotkeys\": \"快捷键\",\n  \"ImageEditor\": \"图像编辑器\",\n  \"ImgEmpty\": \"未保存. 获取的图像为空\",\n  \"ImgFormat\": \"图像格式\",\n  \"ImgSavedClipboard\": \"图片已复制到剪贴板\",\n  \"ImageUploadFailed\": \"图片上传失败\",\n  \"ImageUploadSuccess\": \"图片上传成功\",\n  \"ImageUploading\": \"正在上传图片\",\n  \"IncludeClicks\": \"录制鼠标点击\",\n  \"IncludeCursor\": \"录制光标\",\n  \"IncludeKeys\": \"录制按键\",\n  \"Keymap\": \"键盘映射\",\n  \"Keystrokes\": \"按键\",\n  \"KeystrokesHistoryCount\": \"历史计数\",\n  \"KeystrokesHistorySpacing\": \"历史间距\",\n  \"KeystrokesSeparateFile\": \"另存为文本文件\",\n  \"Language\": \"语言\",\n  \"Left\": \"左\",\n  \"LoopbackSource\": \"扬声器输出源\",\n  \"MaxRecent\": \"最多保存项\",\n  \"MaxTextLength\": \"最大文本长度\",\n  \"MicSource\": \"麦克风源\",\n  \"Minimize\": \"最小化\",\n  \"MinToTrayOnCaptureStart\": \"在录制开始时最小化到托盘\",\n  \"MinTray\": \"最小化到任务栏\",\n  \"MinTrayStartup\": \"在启动时最小化到任务栏\",\n  \"MinTrayClose\": \"关闭时最小化到任务栏\",\n  \"MouseClicks\": \"鼠标点击\",\n  \"MouseMiddleClickColor\": \"中间键点击颜色\",\n  \"MousePointer\": \"鼠标指针\",\n  \"MouseRightClickColor\": \"右键点击颜色\",\n  \"NewWindow\": \"新窗口\",\n  \"No\": \"否\",\n  \"None\": \"没有\",\n  \"Notifications\": \"通知\",\n  \"NotSaved\": \"未保存\",\n  \"NoWebcam\": \"无摄像头\",\n  \"Ok\": \"好的\",\n  \"OnlyAudio\": \"仅音频\",\n  \"Opacity\": \"不透明度\",\n  \"OpenFromClipboard\": \"从剪贴板打开\",\n  \"OpenOutFolder\": \"打开输出目录\",\n  \"OutFolder\": \"输出目录\",\n  \"Overlays\": \"置顶内容\",\n  \"Padding\": \"内边距\",\n  \"Password\": \"密码\",\n  \"Paused\": \"录制已暂停\",\n  \"PauseResume\": \"暂停 | 继续\",\n  \"PauseResumeRecording\": \"暂停/继续录制\",\n  \"Port\": \"端口\",\n  \"Preview\": \"预览\",\n  \"PreStartCountdown\": \"开始前倒计时 (秒)\",\n  \"Proxy\": \"代理\",\n  \"Quality\": \"质量\",\n  \"Radius\": \"半径\",\n  \"Recent\": \"最近\",\n  \"RecordStop\": \"录制 | 停止\",\n  \"Redo\": \"重做\",\n  \"Refresh\": \"刷新\",\n  \"Region\": \"区域\",\n  \"RegionSelector\": \"区域选择器\",\n  \"RemoveFromList\": \"从列表中移除\",\n  \"Reset\": \"重置\",\n  \"Resize\": \"设置尺寸\",\n  \"RestoreDefaults\": \"恢复默认值\",\n  \"Right\": \"右\",\n  \"SaveToClipboard\": \"复制到剪贴板\",\n  \"Screen\": \"全屏\",\n  \"ScreenShot\": \"截图\",\n  \"ScreenShotActiveWindow\": \"截取当前活动窗口\",\n  \"ScreenShotDesktop\": \"截取桌面\",\n  \"ScreenShotSaved\": \"截图已保存\",\n  \"SelectFFmpegFolder\": \"选择FFmpeg目录\",\n  \"SelectOutFolder\": \"选择输出目录\",\n  \"SeparateAudioFiles\": \"每个音频源的独立文件\",\n  \"ShowSysNotify\": \"显示系统托盘通知\",\n  \"SnapToWindow\": \"抓取窗口\",\n  \"Sounds\": \"声音\",\n  \"StartStopRecording\": \"开始/停止录制\",\n  \"StreamingKeys\": \"推流密钥\",\n  \"Timeout\": \"延时\",\n  \"ToggleMouseClicks\": \"切换鼠标点击\",\n  \"ToggleKeystrokes\": \"切换按键\",\n  \"Tools\": \"工具\",\n  \"Top\": \"顶部\",\n  \"TrayIcon\": \"托盘图标\",\n  \"Trim\": \"裁剪\",\n  \"Undo\": \"撤销\",\n  \"UploadToImgur\": \"上传到 Imgur\",\n  \"UseProxyAuth\": \"使用代理验证\",\n  \"UserName\": \"用户名\",\n  \"VarFrameRate\": \"可变帧率\",\n  \"Video\": \"视频\",\n  \"VideoEncoder\": \"视频编码器\",\n  \"VideoSaved\": \"视频已保存\",\n  \"VideoSource\": \"视频源\",\n  \"ViewCrashLogs\": \"查看错误报告\",\n  \"ViewLicenses\": \"查看许可证\",\n  \"ViewOnGitHub\": \"在 GitHub 上查看\",\n  \"WantToTranslate\": \"想提供翻译?\",\n  \"WebCam\": \"摄像头\",\n  \"WebCamSeparateFile\": \"摄像头画面录制到单独的文件中\",\n  \"WebCamView\": \"摄像头视图\",\n  \"Website\": \"网站\",\n  \"Window\": \"窗口\",\n  \"WindowScreenShotTransparency\": \"\",\n  \"Yes\": \"是\"\n}"
  },
  {
    "path": "src/Captura.Loc/Languages/zh-TW.json",
    "content": "{\n  \"About\": \"關於\",\n  \"AccentColor\": \"強調色\",\n  \"Add\": \"新增\",\n  \"AlwaysOnTop\": \"顯示在最上層\",\n  \"Audio\": \"音效\",\n  \"AudioFormat\": \"音訊格式\",\n  \"AudioSaved\": \"音效已儲存\",\n  \"BackColor\": \"背景顏色\",\n  \"BorderColor\": \"邊框顏色\",\n  \"BorderThickness\": \"邊框寬度\",\n  \"Bottom\": \"下\",\n  \"CaptureDuration\": \"錄製時間 (秒)\",\n  \"Center\": \"中\",\n  \"Changelog\": \"更新紀錄\",\n  \"Clear\": \"刪除\",\n  \"ClearRecentList\": \"刪除最近錄製列表\",\n  \"Clipboard\": \"剪貼簿\",\n  \"Close\": \"關閉\",\n  \"Color\": \"顏色\",\n  \"ConfigCodecs\": \"編碼譯碼器設定\",\n  \"Configure\": \"設定\",\n  \"CopyOutPathClipboard\": \"複製輸出文件路徑至剪貼簿\",\n  \"CopyPath\": \"複製路徑\",\n  \"CopyToClipboard\": \"複製到剪貼簿\",\n  \"CornerRadius\": \"圓角半徑\",\n  \"CrashLogs\": \"當機日誌\",\n  \"Crop\": \"剪裁\",\n  \"CustomSize\": \"自訂大小\",\n  \"CustomUrl\": \"自訂 Url\",\n  \"DarkTheme\": \"暗色主題\",\n  \"Delete\": \"刪除\",\n  \"DiscardChanges\": \"放棄變更\",\n  \"Disk\": \"硬碟\",\n  \"Donate\": \"捐贈\",\n  \"DownloadFFmpeg\": \"下載 FFmpeg\",\n  \"Edit\": \"編輯\",\n  \"Elapsed\": \"經過時間\",\n  \"ErrorOccurred\": \"發生錯誤\",\n  \"Exit\": \"退出\",\n  \"FFmpegFolder\": \"FFmpeg 資料夾\",\n  \"FFmpegLog\": \"FFmpeg 紀錄\",\n  \"FileMenu\": \"檔案\",\n  \"FileMenuNew\": \"新增\",\n  \"FileMenuOpen\": \"開啟\",\n  \"FileMenuSave\": \"儲存\",\n  \"FileNaming\": \"檔案命名\",\n  \"FontSize\": \"字體大小\",\n  \"FrameRate\": \"FPS\",\n  \"FullScreen\": \"全螢幕\",\n  \"HideOnFullScreenShot\": \"全螢幕截圖時隱藏\",\n  \"Host\": \"主機\",\n  \"Hotkeys\": \"快捷鍵\",\n  \"ImageEditor\": \"圖片編輯器\",\n  \"ImgEmpty\": \"未儲存. 圖片不存在\",\n  \"ImgFormat\": \"圖片格式\",\n  \"ImgSavedClipboard\": \"圖片已複製到剪貼簿\",\n  \"ImageUploadFailed\": \"圖片上傳失敗\",\n  \"ImageUploadSuccess\": \"圖片上傳成功\",\n  \"ImageUploading\": \"正在上傳圖片\",\n  \"IncludeClicks\": \"顯示滑鼠點擊\",\n  \"IncludeCursor\": \"顯示滑鼠指標\",\n  \"IncludeKeys\": \"顯示鍵盤輸入\",\n  \"Keymap\": \"鍵盤配置\",\n  \"Keystrokes\": \"按鍵\",\n  \"KeystrokesHistoryCount\": \"按鍵顯示數量\",\n  \"KeystrokesHistorySpacing\": \"按鍵顯示行距\",\n  \"KeystrokesSeparateFile\": \"儲存到單獨的文字檔案\",\n  \"Language\": \"語言\",\n  \"Left\": \"左\",\n  \"LoopbackSource\": \"揚聲器輸出來源\",\n  \"MaxRecent\": \"最多儲存數目\",\n  \"MaxTextLength\": \"最大文字長度\",\n  \"MicSource\": \"麥克風來源\",\n  \"Minimize\": \"最小化\",\n  \"MinToTrayOnCaptureStart\": \"開始錄製時最小化\",\n  \"MinTray\": \"最小化到系統匣\",\n  \"MinTrayStartup\": \"啟動時最小化到系統匣\",\n  \"MinTrayClose\": \"關閉時最小化到系統匣\",\n  \"MouseClicks\": \"滑鼠點擊\",\n  \"MouseMiddleClickColor\": \"滑鼠中鍵點擊顏色\",\n  \"MousePointer\": \"滑鼠指標\",\n  \"MouseRightClickColor\": \"滑鼠右鍵點擊顏色\",\n  \"NewWindow\": \"新視窗\",\n  \"No\": \"否\",\n  \"None\": \"無\",\n  \"Notifications\": \"通知\",\n  \"NotSaved\": \"尚未儲存\",\n  \"NoWebcam\": \"無視訊\",\n  \"Ok\": \"確定\",\n  \"OnlyAudio\": \"僅音效\",\n  \"Opacity\": \"不透明度\",\n  \"OpenFromClipboard\": \"從剪貼簿開啟\",\n  \"OpenOutFolder\": \"打開輸出資料夾\",\n  \"OutFolder\": \"輸出資料夾\",\n  \"Overlays\": \"覆蓋效果\",\n  \"Padding\": \"內距\",\n  \"Password\": \"密碼\",\n  \"Paused\": \"錄製暫停\",\n  \"PauseResume\": \"暫停 | 繼續\",\n  \"PauseResumeRecording\": \"暫停/繼續 錄製\",\n  \"Port\": \"連接埠\",\n  \"Preview\": \"預覽\",\n  \"PreStartCountdown\": \"開始前倒數 (秒)\",\n  \"Proxy\": \"代理\",\n  \"Quality\": \"品質\",\n  \"Radius\": \"半徑\",\n  \"Recent\": \"最近\",\n  \"RecordStop\": \"錄製 | 停止\",\n  \"Redo\": \"取消復原\",\n  \"Refresh\": \"重新整理\",\n  \"Region\": \"區域\",\n  \"RegionSelector\": \"區域選擇器\",\n  \"RemoveFromList\": \"從列表中移除\",\n  \"Reset\": \"重置\",\n  \"Resize\": \"設定尺寸\",\n  \"RestoreDefaults\": \"重設為預設值\",\n  \"Right\": \"右\",\n  \"SaveToClipboard\": \"儲存到剪貼簿\",\n  \"Screen\": \"全螢幕\",\n  \"ScreenShot\": \"截圖\",\n  \"ScreenShotActiveWindow\": \"截取目前使用視窗\",\n  \"ScreenShotDesktop\": \"截取桌面\",\n  \"ScreenShotSaved\": \"截圖已儲存\",\n  \"SelectFFmpegFolder\": \"選擇 FFmpeg 資料夾\",\n  \"SelectOutFolder\": \"選擇輸出資料夾\",\n  \"SeparateAudioFiles\": \"每次將音頻來源儲存至單獨的檔案\",\n  \"ShowSysNotify\": \"顯示系統通知\",\n  \"SnapToWindow\": \"貼齊視窗\",\n  \"Sounds\": \"聲音\",\n  \"StartStopRecording\": \"開始/停止錄製\",\n  \"StreamingKeys\": \"串流金鑰\",\n  \"Timeout\": \"延時\",\n  \"ToggleMouseClicks\": \"切換滑鼠點擊\",\n  \"ToggleKeystrokes\": \"切換鍵盤輸入\",\n  \"Tools\": \"工具\",\n  \"Top\": \"上\",\n  \"TrayIcon\": \"系統匣圖示\",\n  \"Trim\": \"修剪\",\n  \"Undo\": \"復原\",\n  \"UploadToImgur\": \"上傳至Imgur\",\n  \"UseProxyAuth\": \"使用代理伺服器驗證\",\n  \"UserName\": \"使用者名稱\",\n  \"VarFrameRate\": \"可變幀數\",\n  \"Video\": \"影片\",\n  \"VideoEncoder\": \"影片編碼器\",\n  \"VideoSaved\": \"影片已儲存\",\n  \"VideoSource\": \"影片來源\",\n  \"ViewCrashLogs\": \"查看當機日誌\",\n  \"ViewLicenses\": \"檢視許可協議\",\n  \"ViewOnGitHub\": \"在 GitHub 上開啟\",\n  \"WantToTranslate\": \"想提供翻譯?\",\n  \"WebCam\": \"網路攝影機\",\n  \"WebCamSeparateFile\": \"錄製視訊到單獨的影像檔案\",\n  \"WebCamView\": \"視訊影像\",\n  \"Website\": \"網站\",\n  \"Window\": \"視窗\",\n  \"WindowScreenShotTransparency\": \"視窗模式下的截圖應該是透明的\",\n  \"Yes\": \"是\"\n}"
  },
  {
    "path": "src/Captura.Loc/ObjectLocalizer.cs",
    "content": "﻿namespace Captura.Loc\n{\n    public class ObjectLocalizer<T> : TextLocalizer\n    {\n        public ObjectLocalizer(T Source, string LocalizationKey) : base(LocalizationKey)\n        {\n            this.Source = Source;            \n        }\n        \n        public T Source { get; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Loc/TextLocalizer.cs",
    "content": "﻿namespace Captura.Loc\n{\n    public class TextLocalizer : NotifyPropertyChanged\n    {\n        public TextLocalizer(string LocalizationKey)\n        {\n            this.LocalizationKey = LocalizationKey;\n\n            LanguageManager.Instance.LanguageChanged += L => RaisePropertyChanged(nameof(Display));\n        }\n        \n        string _key;\n\n        public string LocalizationKey\n        {\n            get => _key;\n            set\n            {\n                _key = value;\n\n                OnPropertyChanged();\n\n                RaisePropertyChanged(nameof(Display));\n            }\n        }\n\n        public string Display => ToString();\n\n        public override string ToString() => LanguageManager.Instance[_key];\n    }\n}\n"
  },
  {
    "path": "src/Captura.MouseKeyHook/Captura.MouseKeyHook.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net472</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"PresentationCore\" />\n    <Reference Include=\"System.Windows.Forms\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"keymaps\\*.json\" Exclude=\"keymaps\\schema.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"MouseKeyHook\" Version=\"5.6.0\" />\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"11.0.2\" />\n    <PackageReference Include=\"System.Reactive\" Version=\"4.1.3\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Captura.MouseKeyHook/IMouseKeyHook.cs",
    "content": "﻿using System;\nusing System.Windows.Forms;\n\nnamespace Captura.MouseKeyHook\n{\n    public interface IMouseKeyHook : IDisposable\n    {\n        event MouseEventHandler MouseUp;\n        event MouseEventHandler MouseDown;\n        event MouseEventHandler MouseClick;\n        event MouseEventHandler MouseDoubleClick;\n        event MouseEventHandler MouseWheel;\n        event MouseEventHandler MouseMove;\n\n        event MouseEventHandler MouseDragStarted;\n        event MouseEventHandler MouseDragFinished;\n\n        event KeyEventHandler KeyUp;\n        event KeyEventHandler KeyDown;\n        event KeyPressEventHandler KeyPress;\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/KeyOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Windows.Forms;\nusing Captura.Video;\n\nnamespace Captura.MouseKeyHook\n{\n    public class KeyOverlay : IOverlay\n    {\n        readonly KeystrokesSettings _settings;\n        readonly KeyRecords _records;\n        readonly KeymapViewModel _keymap;\n        bool _modifierSingleDown;\n\n        public KeyOverlay(IMouseKeyHook Hook,\n            KeystrokesSettings Settings,\n            KeymapViewModel Keymap)\n        {\n            _settings = Settings;\n            _keymap = Keymap;\n\n            _records = new KeyRecords(Settings.HistoryCount);\n\n            Hook.KeyDown += OnKeyDown;\n            Hook.KeyUp += OnKeyUp;\n        }\n\n        public void Dispose() { }\n\n        public void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null)\n        {\n            if (!_settings.Display)\n                return;\n\n            if (_records?.Last == null)\n                return;\n\n            var offsetY = 0f;\n            var fontSize = _settings.FontSize;\n            byte opacity = 255;\n\n            var index = 0;\n\n            foreach (var keyRecord in _records)\n            {\n                if ((DateTime.Now - keyRecord.TimeStamp).TotalSeconds > _records.Size * _settings.Timeout)\n                    continue;\n\n                using (var font = Editor.GetFont(_settings.FontFamily, Math.Max(1, fontSize)))\n                {\n                    DrawKeys(_settings, Editor, keyRecord.Display, font, opacity, offsetY);\n\n                    var height = Editor.MeasureString(\"A\", font).Height;\n\n                    offsetY += height + _settings.HistorySpacing;\n\n                    offsetY += _settings.VerticalPadding * 2 + _settings.BorderThickness * 2;\n                }\n\n                if (++index == 1)\n                {\n                    fontSize = Math.Max(1, fontSize - 5);\n                    opacity = 200;\n                }\n            }\n        }\n\n        static Color ApplyOpacity(Color Color, int Opacity)\n        {\n            var alpha = (int)Math.Round((Opacity / 255.0) * (Color.A / 255.0) * 255);\n\n            return Color.FromArgb(alpha, Color);\n        }\n\n        static void DrawKeys(KeystrokesSettings KeystrokesSettings, IEditableFrame Editor, string Text, IFont Font, byte Opacity, float OffsetY)\n        {\n            var size = Editor.MeasureString(Text, Font);\n\n            int paddingX = KeystrokesSettings.HorizontalPadding, paddingY = KeystrokesSettings.VerticalPadding;\n\n            var rect = new RectangleF(GetLeft(KeystrokesSettings, Editor.Width, size.Width),\n                GetTop(KeystrokesSettings, Editor.Height, size.Height, OffsetY),\n                size.Width + 2 * paddingX,\n                size.Height + 2 * paddingY);\n\n            Editor.FillRectangle(ApplyOpacity(KeystrokesSettings.BackgroundColor, Opacity),\n                rect,\n                KeystrokesSettings.CornerRadius);\n\n            Editor.DrawString(Text,\n                Font,\n                ApplyOpacity(KeystrokesSettings.FontColor, Opacity),\n                new RectangleF(rect.Left + paddingX, rect.Top + paddingY, size.Width, size.Height));\n\n            var border = KeystrokesSettings.BorderThickness;\n\n            if (border > 0)\n            {\n                rect = new RectangleF(rect.Left - border / 2f, rect.Top - border / 2f, rect.Width + border, rect.Height + border);\n\n                Editor.DrawRectangle(ApplyOpacity(KeystrokesSettings.BorderColor, Opacity), border,\n                    rect,\n                    KeystrokesSettings.CornerRadius);\n            }\n        }\n\n        public static float GetLeft(TextOverlaySettings KeystrokesSettings, float FullWidth, float TextWidth)\n        {\n            var x = KeystrokesSettings.X;\n            var padding = KeystrokesSettings.HorizontalPadding;\n\n            switch (KeystrokesSettings.HorizontalAlignment)\n            {\n                case Alignment.Start:\n                    return x;\n\n                case Alignment.End:\n                    return FullWidth - x - TextWidth - 2 * padding;\n\n                case Alignment.Center:\n                    return FullWidth / 2 + x - TextWidth / 2 - padding;\n\n                default:\n                    return 0;\n            }\n        }\n\n        public static float GetTop(TextOverlaySettings KeystrokesSettings, float FullHeight, float TextHeight, float Offset = 0)\n        {\n            var y = KeystrokesSettings.Y;\n            var padding = KeystrokesSettings.VerticalPadding;\n\n            switch (KeystrokesSettings.VerticalAlignment)\n            {\n                case Alignment.Start:\n                    return y + Offset;\n\n                case Alignment.End:\n                    return FullHeight - y - TextHeight - 2 * padding - Offset;\n\n                case Alignment.Center:\n                    return FullHeight / 2 + y - TextHeight / 2 - padding + Offset;\n\n                default:\n                    return 0;\n            }\n        }\n\n        void OnKeyUp(object Sender, KeyEventArgs Args)\n        {\n            if (!_settings.Display)\n            {\n                _records.Clear();\n\n                return;\n            }\n\n            var record = new KeyRecord(Args, _keymap);\n\n            var display = record.Display;\n\n            if (display == _keymap.Control\n                || display == _keymap.Alt\n                || display == _keymap.Shift)\n            {\n                if (_records.Last?.Display == display)\n                {\n                    _records.Last = new RepeatKeyRecord(record, _settings);\n                }\n                else if (_records.Last is RepeatKeyRecord repeat && repeat.Repeated.Display == display)\n                {\n                    repeat.Increment();\n                }\n                else if (_modifierSingleDown)\n                {\n                    _records.Add(record);\n                }\n            }\n        }\n\n        void OnKeyDown(object Sender, KeyEventArgs Args)\n        {\n            if (!_settings.Display)\n            {\n                _records.Clear();\n\n                return;\n            }\n\n            _modifierSingleDown = false;\n\n            var record = new KeyRecord(Args, _keymap);\n\n            if (_records.Last == null)\n            {\n                _records.Add(record);\n\n                return;\n            }\n\n            var elapsed = (record.TimeStamp - _records.Last.TimeStamp).TotalSeconds;\n\n            var display = record.Display;\n            var lastDisplay = _records.Last.Display;\n\n            if (display.Length == 1\n                && (_records.Last is DummyKeyRecord || lastDisplay.Length == 1)\n                && display.Length + lastDisplay.Length <= _settings.MaxTextLength\n                && elapsed <= _settings.Timeout)\n            {\n                _records.Last = new DummyKeyRecord(lastDisplay + display);\n            }\n            else if (display == _keymap.Control\n                     || display == _keymap.Alt\n                     || display == _keymap.Shift)\n            {\n                // Handled on Key Up\n                _modifierSingleDown = true;\n            }\n            else if (_records.Last is KeyRecord keyRecord && keyRecord.Display == display)\n            {\n                _records.Last = new RepeatKeyRecord(record, _settings);\n            }\n            else if (_records.Last is RepeatKeyRecord repeatRecord && repeatRecord.Repeated.Display == display)\n            {\n                repeatRecord.Increment();\n            }\n            else\n            {\n                _records.Add(record);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/KeyRecord/DummyKeyRecord.cs",
    "content": "using System;\n\nnamespace Captura.MouseKeyHook\n{\n    class DummyKeyRecord : IKeyRecord\n    {\n        public DummyKeyRecord(string Display)\n        {\n            this.Display = Display;\n\n            TimeStamp = DateTime.Now;\n        }\n\n        public bool Control => false;\n        public bool Shift => false;\n        public bool Alt => false;\n\n        public DateTime TimeStamp { get; }\n\n        public string Display { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/KeyRecord/IKeyRecord.cs",
    "content": "using System;\n\nnamespace Captura.MouseKeyHook\n{\n    interface IKeyRecord\n    {\n        DateTime TimeStamp { get; }\n\n        string Display { get; }\n\n        bool Control { get; }\n        bool Shift { get; }\n        bool Alt { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/KeyRecord/KeyRecord.cs",
    "content": "﻿using System;\nusing System.Windows.Forms;\n\nnamespace Captura.MouseKeyHook\n{\n    class KeyRecord : IKeyRecord\n    {\n        readonly KeyEventArgs _eventArgs;\n        readonly KeymapViewModel _keymap;\n\n        readonly bool _capsLock;\n\n        public KeyRecord(KeyEventArgs KeyEventArgs, KeymapViewModel Keymap)\n        {\n            _keymap = Keymap;\n            _eventArgs = KeyEventArgs;\n            TimeStamp = DateTime.Now;\n\n            Key = KeyEventArgs.KeyCode;\n            Control = KeyEventArgs.Control;\n            Shift = KeyEventArgs.Shift;\n            Alt = KeyEventArgs.Alt;\n\n            _capsLock = Console.CapsLock;\n\n            Display = GetDisplay();\n        }\n\n        public DateTime TimeStamp { get; }\n\n        public Keys Key { get; }\n\n        bool IsNum => (Key >= Keys.D0 && Key <= Keys.D9) || (Key >= Keys.NumPad0 && Key <= Keys.NumPad9);\n\n        int AsNum\n        {\n            get\n            {\n                if (Key >= Keys.D0 && Key <= Keys.D9)\n                    return Key - Keys.D0;\n\n                return Key - Keys.NumPad0;\n            }\n        }\n\n        public bool Control { get; }\n        public bool Shift { get; }\n        public bool Alt { get; }\n        \n        public string Display { get; }\n        \n        string Modifiers\n        {\n            get\n            {\n                var result = \"\";\n\n                if (Control)\n                {\n                    result += $\"{_keymap.Control} + \";\n                }\n\n                if (Shift)\n                {\n                    result += $\"{_keymap.Shift} + \";\n                }\n\n                if (Alt)\n                {\n                    result += $\"{_keymap.Alt} + \";\n                }\n\n                return result;\n            }\n        }\n\n        string GetDisplay()\n        {\n            switch (Key)\n            {\n                case Keys.Shift:\n                case Keys.ShiftKey:\n                case Keys.LShiftKey:\n                case Keys.RShiftKey:\n                    return _keymap.Shift;\n\n                case Keys.Control:\n                case Keys.ControlKey:\n                case Keys.LControlKey:\n                case Keys.RControlKey:\n                    return _keymap.Control;\n\n                case Keys.Alt:\n                case Keys.Menu:\n                case Keys.LMenu:\n                case Keys.RMenu:\n                    return _keymap.Alt;\n            }\n\n            var found = _keymap.Find(Key, new ModifierStates\n            {\n                CapsLock = _capsLock,\n                Alt = Alt,\n                Control = Control,\n                Shift = Shift\n            });\n\n            if (found != null)\n                return found;\n\n            if (_eventArgs.Modifiers == 0)\n            {\n                found = _keymap.Find(Key, new ModifierStates\n                {\n                    CapsLock = _capsLock\n                });\n\n                return found ?? Key.ToString();\n            }\n\n            if (IsNum)\n            {\n                return Modifiers + AsNum;\n            }\n\n            // Alphabet\n            if (Key >= Keys.A && Key <= Keys.Z)\n            {\n                return Modifiers + Key.ToString().ToUpper();\n            }\n\n            found = _keymap.Find(Key, new ModifierStates\n            {\n                CapsLock = _capsLock\n            });\n\n            return Modifiers + (found ?? Key.ToString());\n        }\n\n        public override string ToString() => Display;\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/KeyRecord/KeyRecords.cs",
    "content": "using System.Collections;\nusing System.Collections.Generic;\n\nnamespace Captura.MouseKeyHook\n{\n    class KeyRecords : IEnumerable<IKeyRecord>\n    {\n        readonly List<IKeyRecord> _records = new List<IKeyRecord>();\n\n        public KeyRecords(int Size)\n        {\n            this.Size = Size;\n        }\n\n        public int Size { get; }\n\n        public void Clear() => _records.Clear();\n\n        public void Add(IKeyRecord KeyRecord)\n        {\n            if (_records.Count == Size)\n            {\n                _records.RemoveAt(0);\n            }\n\n            _records.Add(KeyRecord);\n        }\n        \n        public IKeyRecord Last\n        {\n            get => _records.Count == 0 ? null : _records [_records.Count - 1];\n            set\n            {\n                if (_records.Count == 0)\n                    _records.Add(value);\n                else _records[_records.Count - 1] = value;\n            }\n        } \n\n        public IEnumerator<IKeyRecord> GetEnumerator()\n        {\n            for (var i = _records.Count - 1; i >= 0; --i)\n                yield return _records[i];\n        }\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/KeyRecord/RepeatKeyRecord.cs",
    "content": "using System;\n\nnamespace Captura.MouseKeyHook\n{\n    class RepeatKeyRecord : IKeyRecord\n    {\n        readonly KeystrokesSettings _settings;\n\n        public RepeatKeyRecord(KeyRecord Repeated, KeystrokesSettings Settings)\n        {\n            this.Repeated = Repeated;\n            _settings = Settings;\n\n            Increment();\n        }\n\n        public bool Control => Repeated.Control;\n        public bool Shift => Repeated.Shift;\n        public bool Alt => Repeated.Alt;\n\n        public DateTime TimeStamp { get; private set; }\n\n        public KeyRecord Repeated { get; }\n\n        public int Repeat { get; private set; } = 1;\n\n        public void Increment()\n        {\n            ++Repeat;\n\n            TimeStamp = DateTime.Now;\n        }\n\n        public string Display => _settings.ShowRepeatCounter\n            ? $\"{Repeated} x {Repeat}\"\n            : Repeated.ToString();\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/KeymapViewModel.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Windows.Forms;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace Captura.MouseKeyHook\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class KeymapViewModel : NotifyPropertyChanged\n    {\n        Keymap _keymap;\n\n        public const string DefaultKeymapFileName = \"en\";\n\n        public class KeymapItem\n        {\n            public KeymapItem(string FileName, string Name)\n            {\n                this.FileName = FileName;\n                this.Name = Name;\n            }\n\n            public string FileName { get; }\n\n            public string Name { get; }\n        }\n\n        public KeymapViewModel()\n        {\n            var keymapDir = Path.Combine(ServiceProvider.AppDir, \"keymaps\");\n\n            if (Directory.Exists(keymapDir))\n            {\n                var files = Directory.EnumerateFiles(keymapDir, \"*.json\");\n\n                _keymaps.AddRange(files\n                    .Where(M => !M.Contains(\"schema\"))\n                    .Select(M =>\n                    {\n                        var content = File.ReadAllText(M);\n\n                        var name = JObject.Parse(content)[\"Name\"];\n\n                        return new KeymapItem(M, name.ToString());\n                    }));\n            }\n\n            if (AvailableKeymaps.Count == 0)\n            {\n                var empty = new KeymapItem(\"\", \"Empty\");\n\n                _keymap = new Keymap();\n\n                _keymaps.Add(empty);\n\n                _selectedKeymap = empty;\n            }\n            else SelectedKeymap = AvailableKeymaps[0];\n        }\n\n        readonly List<KeymapItem> _keymaps = new List<KeymapItem>();\n\n        public IReadOnlyList<KeymapItem> AvailableKeymaps => _keymaps;\n\n        KeymapItem _selectedKeymap;\n\n        public KeymapItem SelectedKeymap\n        {\n            get => _selectedKeymap;\n            set\n            {\n                if (!File.Exists(value.FileName))\n                    return;\n\n                try\n                {\n                    Parse(File.ReadAllText(value.FileName));\n\n                    _selectedKeymap = value;\n\n                    OnPropertyChanged();\n                }\n                catch\n                {\n                    // Ignore errors\n                }\n            }\n        }\n\n        void Init(Keymap Keymap)\n        {\n            _keymap = Keymap;\n\n            Control = Find(Keys.Control, ModifierStates.Empty) ?? nameof(Control);\n            Shift = Find(Keys.Shift, ModifierStates.Empty) ?? nameof(Shift);\n            Alt = Find(Keys.Alt, ModifierStates.Empty) ?? nameof(Alt);\n        }\n\n        void Parse(string Content)\n        {\n            var keymap = new Keymap();\n\n            JsonConvert.PopulateObject(Content, keymap);\n            \n            Init(keymap);\n        }\n\n        public string Find(Keys Key, ModifierStates Modifiers)\n        {\n            return _keymap.Mappings\n                .Where(M => M.On.Any(S => S.Control == Modifiers.Control\n                              && S.Alt == Modifiers.Alt\n                              && S.Shift == Modifiers.Shift\n                              && S.CapsLock == Modifiers.CapsLock))\n                .SelectMany(M => M.Keys)\n                .FirstOrDefault(M => M.Key == Key).Value;\n        }\n\n        public string Control { get; private set; } = nameof(Control);\n\n        public string Shift { get; private set; } = nameof(Shift);\n\n        public string Alt { get; private set; } = nameof(Alt);\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/Models/Keymap.cs",
    "content": "﻿// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global\n// ReSharper disable MemberCanBePrivate.Global\n\nusing System.Collections.Generic;\n\nnamespace Captura.MouseKeyHook\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class Keymap\n    {\n        public string Name { get; set; }\n\n        public List<MappingGroup> Mappings { get; } = new List<MappingGroup>();\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/Models/KeystrokesSettings.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.MouseKeyHook\n{\n    public class KeystrokesSettings : TextOverlaySettings\n    {\n        public int MaxTextLength\n        {\n            get => Get(15);\n            set => Set(value);\n        }\n\n        public int Timeout\n        {\n            get => Get(2);\n            set => Set(value);\n        }\n\n        public int HistoryCount\n        {\n            get => Get(6);\n            set => Set(value);\n        }\n\n        public int HistorySpacing\n        {\n            get => Get(10);\n            set => Set(value);\n        }\n\n        public bool ShowRepeatCounter\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n\n        public string KeymapName\n        {\n            get => Get(KeymapViewModel.DefaultKeymapFileName);\n            set => Set(value);\n        }\n\n        public bool SeparateTextFile\n        {\n            get => Get(false);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/Models/MappingGroup.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Windows.Forms;\n\nnamespace Captura.MouseKeyHook\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class MappingGroup\n    {\n        public List<ModifierStates> On { get; set; }\n\n        public Dictionary<Keys, string> Keys { get; } = new Dictionary<Keys, string>();\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/Models/ModifierStates.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Windows.Input;\n\nnamespace Captura.MouseKeyHook\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ModifierStates\n    {\n        public static ModifierStates GetCurrent()\n        {\n            var modifiers = Keyboard.Modifiers;\n\n            var modifierStates = new ModifierStates\n            {\n                Control = modifiers.HasFlag(ModifierKeys.Control),\n                Shift = modifiers.HasFlag(ModifierKeys.Shift),\n                Alt = modifiers.HasFlag(ModifierKeys.Alt),\n                CapsLock = Console.CapsLock\n            };\n\n            return modifierStates;\n        }\n\n        public string ToString(KeymapViewModel Keymap)\n        {\n            var pressed = new List<string>();\n\n            if (Control)\n                pressed.Add(Keymap.Control);\n\n            if (Shift)\n                pressed.Add(Keymap.Shift);\n\n            if (Alt)\n                pressed.Add(Keymap.Alt);\n\n            if (pressed.Count == 0)\n                return \"\";\n\n            return string.Join(\" + \", pressed);\n        }\n\n        public static ModifierStates Empty { get; } = new ModifierStates();\n\n        public bool Control { get; set; }\n\n        public bool Shift { get; set; }\n\n        public bool Alt { get; set; }\n\n        public bool CapsLock { get; set; }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/Models/MouseClickSettings.cs",
    "content": "﻿using System.Drawing;\n\nnamespace Captura.MouseKeyHook\n{\n    public class MouseClickSettings : MouseOverlaySettings\n    {\n        public Color RightClickColor\n        {\n            get => Get(Color.FromArgb(3, 169, 244));\n            set => Set(value);\n        }\n\n        public Color MiddleClickColor\n        {\n            get => Get(Color.FromArgb(76, 175, 80));\n            set => Set(value);\n        }\n\n        public bool DisplayScroll\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n\n        public Color ScrollCircleColor\n        {\n            get => Get(Color.FromArgb(239, 83, 80));\n            set => Set(value);\n        }\n\n        public Color ScrollArrowColor\n        {\n            get => Get(Color.FromArgb(33, 33, 33));\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/MouseClickOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Windows.Forms;\nusing Captura.Video;\n\nnamespace Captura.MouseKeyHook\n{\n    public class MouseClickOverlay : IOverlay\n    {\n        readonly MouseClickSettings _settings;\n        bool _clicked;\n        MouseButtons _buttons;\n\n        public MouseClickOverlay(IMouseKeyHook Hook,\n            MouseClickSettings Settings)\n        {\n            _settings = Settings;\n\n            Hook.MouseDown += (S, E) =>\n            {\n                _clicked = true;\n\n                _buttons = E.Button;\n            };\n\n            Hook.MouseUp += (S, E) => _clicked = false;\n        }\n\n        public void Dispose() { }\n\n        public void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null)\n        {\n            if (!_settings.Display)\n                return;\n\n            if (_clicked && _currentMouseRatio < MouseRatioMax)\n            {\n                _currentMouseRatio += MouseRatioDeltaUp;\n\n                if (_currentMouseRatio > MouseRatioMax)\n                {\n                    _currentMouseRatio = MouseRatioMax;\n                }\n            }\n            else if (!_clicked && _currentMouseRatio > MouseRatioMin)\n            {\n                _currentMouseRatio -= MouseRatioDeltaDown;\n\n                if (_currentMouseRatio < MouseRatioMin)\n                {\n                    _currentMouseRatio = MouseRatioMin;\n                }\n            }\n\n            if (_currentMouseRatio > MouseRatioMin)\n            {\n                var clickRadius = _settings.Radius * _currentMouseRatio;\n\n                var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n                var curPos = platformServices.CursorPosition;\n\n                if (PointTransform != null)\n                    curPos = PointTransform(curPos);\n\n                var d = clickRadius * 2;\n\n                var x = curPos.X - clickRadius;\n                var y = curPos.Y - clickRadius;\n\n                var color = GetClickCircleColor();\n\n                color = Color.FromArgb(ToByte(color.A * _currentMouseRatio), color);\n\n                Editor.FillEllipse(color, new RectangleF(x, y, d, d));\n\n                var border = _settings.BorderThickness * _currentMouseRatio;\n\n                if (border > 0)\n                {\n                    x -= border / 2f;\n                    y -= border / 2f;\n                    d += border;\n\n                    var borderColor = _settings.BorderColor;\n\n                    borderColor = Color.FromArgb(ToByte(borderColor.A * _currentMouseRatio), borderColor);\n\n                    Editor.DrawEllipse(borderColor, border, new RectangleF(x, y, d, d));\n                }\n            }\n        }\n\n        Color GetClickCircleColor()\n        {\n            if (_buttons.HasFlag(MouseButtons.Right))\n            {\n                return _settings.RightClickColor;\n            }\n\n            if (_buttons.HasFlag(MouseButtons.Middle))\n            {\n                return _settings.MiddleClickColor;\n            }\n\n            return _settings.Color;\n        }\n\n        static byte ToByte(double Value)\n        {\n            if (Value > 255)\n                return 255;\n\n            if (Value < 0)\n                return 0;\n\n            return (byte)Value;\n        }\n\n        float _currentMouseRatio;\n        const float MouseRatioDeltaUp = 0.9f;\n        const float MouseRatioDeltaDown = 0.25f;\n        const float MouseRatioMin = 0.6f;\n        const float MouseRatioMax = 1.2f;\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/MouseKeyHook.cs",
    "content": "﻿using Gma.System.MouseKeyHook;\nusing System.Windows.Forms;\n\nnamespace Captura.MouseKeyHook\n{\n    public class MouseKeyHook : IMouseKeyHook\n    {\n        readonly IKeyboardMouseEvents _hook;\n\n        public MouseKeyHook()\n        {\n            _hook = Hook.GlobalEvents();\n        }\n\n        public event MouseEventHandler MouseUp\n        {\n            add => _hook.MouseUp += value;\n            remove => _hook.MouseUp -= value;\n        }\n\n        public event MouseEventHandler MouseDown\n        {\n            add => _hook.MouseDown += value;\n            remove => _hook.MouseDown -= value;\n        }\n\n        public event MouseEventHandler MouseClick\n        {\n            add => _hook.MouseClick += value;\n            remove => _hook.MouseClick -= value;\n        }\n\n        public event MouseEventHandler MouseDoubleClick\n        {\n            add => _hook.MouseDoubleClick += value;\n            remove => _hook.MouseDoubleClick -= value;\n        }\n\n        public event MouseEventHandler MouseWheel\n        {\n            add => _hook.MouseWheel += value;\n            remove => _hook.MouseWheel -= value;\n        }\n\n        public event MouseEventHandler MouseMove\n        {\n            add => _hook.MouseMove += value;\n            remove => _hook.MouseMove -= value;\n        }\n\n        public event MouseEventHandler MouseDragStarted\n        {\n            add => _hook.MouseDragStarted += value;\n            remove => _hook.MouseDragStarted -= value;\n        }\n\n        public event MouseEventHandler MouseDragFinished\n        {\n            add => _hook.MouseDragFinished += value;\n            remove => _hook.MouseDragFinished -= value;\n        }\n\n        public event KeyEventHandler KeyUp\n        {\n            add => _hook.KeyUp += value;\n            remove => _hook.KeyUp -= value;\n        }\n\n        public event KeyEventHandler KeyDown\n        {\n            add => _hook.KeyDown += value;\n            remove => _hook.KeyDown -= value;\n        }\n\n        public event KeyPressEventHandler KeyPress\n        {\n            add => _hook.KeyPress += value;\n            remove => _hook.KeyPress -= value;\n        }\n\n        public void Dispose()\n        {\n            _hook.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.MouseKeyHook/MouseKeyOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.IO;\nusing Captura.Video;\n\nnamespace Captura.MouseKeyHook\n{\n    /// <summary>\n    /// Draws Mouse Clicks and/or Keystrokes on an Image.\n    /// </summary>\n    public class MouseKeyOverlay : IOverlay\n    {\n        #region Fields\n        readonly IMouseKeyHook _hook;\n        readonly KeystrokesSettings _keystrokesSettings;\n        readonly IOverlay _mouseClickOverlay,\n            _keyOverlay,\n            _scrollOverlay;\n\n        readonly KeymapViewModel _keymap;\n        readonly TextWriter _textWriter;\n        #endregion\n        \n        /// <summary>\n        /// Creates a new instance of <see cref=\"MouseKeyHook\"/>.\n        /// </summary>\n        public MouseKeyOverlay(IMouseKeyHook Hook,\n            MouseClickSettings MouseClickSettings,\n            KeystrokesSettings KeystrokesSettings,\n            KeymapViewModel Keymap,\n            string FileName,\n            Func<TimeSpan> Elapsed)\n        {\n            _keystrokesSettings = KeystrokesSettings;\n            _keymap = Keymap;\n\n            _hook = Hook;\n            _mouseClickOverlay = new MouseClickOverlay(_hook, MouseClickSettings);\n            _scrollOverlay = new ScrollOverlay(_hook, MouseClickSettings);\n\n            if (KeystrokesSettings.SeparateTextFile)\n            {\n                _textWriter = InitKeysToTextFile(FileName, Elapsed);\n            }\n            else _keyOverlay = new KeyOverlay(_hook, KeystrokesSettings, Keymap);\n        }\n\n        TextWriter InitKeysToTextFile(string FileName, Func<TimeSpan> Elapsed)\n        {\n            var dir = Path.GetDirectoryName(FileName);\n            var fileNameWoExt = Path.GetFileNameWithoutExtension(FileName);\n\n            var targetName = $\"{fileNameWoExt}.keys.txt\";\n\n            var path = dir == null ? targetName : Path.Combine(dir, targetName);\n\n            var keystrokeFileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read);\n            var textWriter = new StreamWriter(keystrokeFileStream);\n\n            _hook.KeyDown += (S, E) =>\n            {\n                if (!_keystrokesSettings.Display)\n                {\n                    return;\n                }\n\n                var record = new KeyRecord(E, _keymap);\n\n                _textWriter.WriteLine($\"{Elapsed.Invoke()}: {record.Display}\");\n            };\n\n            return textWriter;\n        }\n        \n        /// <summary>\n        /// Draws overlay.\n        /// </summary>\n        public void Draw(IEditableFrame Editor, Func<Point, Point> Transform = null)\n        {\n            _mouseClickOverlay?.Draw(Editor, Transform);\n            _scrollOverlay?.Draw(Editor, Transform);\n\n            _keyOverlay?.Draw(Editor, Transform);\n        }\n\n        /// <summary>\n        /// Frees all resources used by this object.\n        /// </summary>\n        public void Dispose()\n        {\n            _hook?.Dispose();\n\n            _mouseClickOverlay?.Dispose();\n            _scrollOverlay?.Dispose();\n            _keyOverlay?.Dispose();\n\n            _textWriter?.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/ScrollOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Windows.Forms;\nusing Captura.Video;\n\nnamespace Captura.MouseKeyHook\n{\n    // TODO: Shows horizontal scroll incorrectly as vertical.\n    // The MouseKeyHook library doesn't provide an option\n    // to distinguish between horizontal and vertical scrolls.\n    public class ScrollOverlay : IOverlay\n    {\n        readonly MouseClickSettings _settings;\n        MouseEventArgs _lastArgs;\n\n        public ScrollOverlay(IMouseKeyHook Hook,\n            MouseClickSettings Settings)\n        {\n            _settings = Settings;\n\n            Hook.MouseWheel += (S, E) => _lastArgs = E;\n        }\n\n        public void Dispose() { }\n\n        public void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null)\n        {\n            if (!_settings.DisplayScroll)\n                return;\n\n            if (_lastArgs is { } args)\n            {\n                var p = args.Location;\n                var r = _settings.Radius;\n                var d = 2 * r;\n\n                Editor.FillEllipse(_settings.ScrollCircleColor, new RectangleF(p.X - r, p.Y - r, d, d));\n\n                var above = new Point(p.X, p.Y + r / 2);\n                var below = new Point(p.X, p.Y - r / 2);\n\n                // Scroll down\n                if (args.Delta < 0)\n                {\n                    (above, below) = (below, above);\n                }\n\n                Editor.DrawArrow(above, below, _settings.ScrollArrowColor, r / 4f);\n\n                _lastArgs = null;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/Steps/IRecordStep.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.MouseKeyHook.Steps\n{\n    interface IRecordStep\n    {\n        void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform);\n\n        bool Merge(IRecordStep NextStep);\n    }\n}\n"
  },
  {
    "path": "src/Captura.MouseKeyHook/Steps/KeyModifiedStep.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.MouseKeyHook.Steps\n{\n    abstract class KeyModifiedStep : IRecordStep\n    {\n        readonly KeystrokesSettings _keystrokesSettings;\n        readonly ModifierStates _modifierStates;\n        readonly KeymapViewModel _keymap;\n\n        public KeyModifiedStep(KeystrokesSettings Settings,\n            KeymapViewModel Keymap)\n        {\n            _keymap = Keymap;\n            _keystrokesSettings = Settings;\n            _modifierStates = ModifierStates.GetCurrent();\n        }\n\n        public virtual void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform)\n        {\n            KeyStep.DrawString(Editor, _modifierStates.ToString(_keymap), _keystrokesSettings);\n        }\n\n        public virtual bool Merge(IRecordStep NextStep)\n        {\n            switch (NextStep)\n            {\n                case KeyStep keyStep:\n                    if (_modifierStates.Control && keyStep.Text == _keymap.Control)\n                        return true;\n\n                    if (_modifierStates.Shift && keyStep.Text == _keymap.Shift)\n                        return true;\n\n                    if (_modifierStates.Alt && keyStep.Text == _keymap.Alt)\n                        return true;\n                    break;\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.MouseKeyHook/Steps/KeyStep.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.MouseKeyHook.Steps\n{\n    class KeyStep : IRecordStep\n    {\n        public string Text { get; private set; }\n\n        readonly KeystrokesSettings _settings;\n        readonly bool _mergeable;\n        int _repeat;\n\n        public KeyStep(KeystrokesSettings Settings,\n            KeyRecord KeyRecord)\n        {\n            _settings = Settings;\n\n            // TODO: Handle Modifiers keys on KeyUp like in KeyOverlay\n            Text = KeyRecord.Display;\n\n            _mergeable = Text.Length == 1;\n        }\n\n        public static void DrawString(IEditableFrame Editor, string Text, KeystrokesSettings Settings)\n        {\n            if (string.IsNullOrWhiteSpace(Text))\n                return;\n\n            using var font = Editor.GetFont(Settings.FontFamily, Settings.FontSize);\n            var size = Editor.MeasureString(Text, font);\n\n            int paddingX = Settings.HorizontalPadding,\n                paddingY = Settings.VerticalPadding;\n\n            var rect = new RectangleF(KeyOverlay.GetLeft(Settings, Editor.Width, size.Width),\n                KeyOverlay.GetTop(Settings, Editor.Height, size.Height),\n                size.Width + 2 * paddingX,\n                size.Height + 2 * paddingY);\n\n            Editor.FillRectangle(Settings.BackgroundColor,\n                rect,\n                Settings.CornerRadius);\n\n            Editor.DrawString(Text,\n                font,\n                Settings.FontColor,\n                new RectangleF(rect.Left + paddingX, rect.Top + paddingY, size.Width, size.Height));\n\n            var border = Settings.BorderThickness;\n\n            if (border > 0)\n            {\n                rect = new RectangleF(rect.Left - border / 2f, rect.Top - border / 2f, rect.Width + border, rect.Height + border);\n\n                Editor.DrawRectangle(Settings.BorderColor,\n                    border,\n                    rect,\n                    Settings.CornerRadius);\n            }\n        }\n\n        public void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform)\n        {\n            var repeat = (_repeat == 0 ? \"\" : $\" x {_repeat + 1}\");\n\n            var text = $\"{Text}{repeat}\";\n\n            DrawString(Editor, text, _settings);\n        }\n\n        public bool Merge(IRecordStep NextStep)\n        {\n            if (NextStep is KeyStep nextStep)\n            {\n                if (_repeat == 0 && _mergeable && nextStep.Text.Length == 1)\n                {\n                    Text += nextStep.Text;\n                    return true;\n                }\n\n                if (Text == nextStep.Text)\n                {\n                    ++_repeat;\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.MouseKeyHook/Steps/MouseClickStep.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Windows.Forms;\n\nnamespace Captura.MouseKeyHook.Steps\n{\n    class MouseClickStep : KeyModifiedStep\n    {\n        readonly MouseClickSettings _settings;\n        public MouseEventArgs Args { get; private set; }\n\n        public DateTime Timestamp { get; }\n\n        // Default Double-click time on Windows is 500ms\n        const int DoubleClickDelta = 500;\n\n        public MouseClickStep(MouseClickSettings Settings,\n            KeystrokesSettings KeystrokesSettings,\n            MouseEventArgs Args,\n            KeymapViewModel Keymap) : base(KeystrokesSettings, Keymap)\n        {\n            _settings = Settings;\n            this.Args = Args;\n\n            Timestamp = DateTime.Now;\n        }\n\n        public override bool Merge(IRecordStep NextStep)\n        {\n            switch (NextStep)\n            {\n                case MouseClickStep mouseClickStep when Args.Clicks == 1:\n                    var delta = (mouseClickStep.Timestamp - Timestamp).TotalMilliseconds;\n\n                    if (mouseClickStep.Args.Clicks == 2 && delta < DoubleClickDelta)\n                    {\n                        Args = mouseClickStep.Args;\n\n                        return true;\n                    }\n                    break;\n            }\n\n            return base.Merge(NextStep);\n        }\n\n        public override void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null)\n        {\n            var curPos = Args.Location;\n\n            if (PointTransform != null)\n                curPos = PointTransform(curPos);\n\n            float clickRadius = _settings.Radius;\n\n            var d = clickRadius * 2;\n\n            var x = curPos.X - clickRadius;\n            var y = curPos.Y - clickRadius;\n\n            var color = GetClickCircleColor();\n\n            Editor.FillEllipse(color, new RectangleF(x, y, d, d));\n\n            var border = _settings.BorderThickness;\n\n            if (border > 0)\n            {\n                x -= border / 2f;\n                y -= border / 2f;\n                d += border;\n\n                var borderColor = _settings.BorderColor;\n\n                Editor.DrawEllipse(borderColor, border, new RectangleF(x, y, d, d));\n            }\n\n            if (Args.Clicks > 1)\n            {\n                var font = Editor.GetFont(\"Arial\", 15);\n                Editor.DrawString(Args.Clicks.ToString(), font, Color.Black, new RectangleF(x + 10, y + 10, d, d));\n            }\n\n            base.Draw(Editor, PointTransform);\n        }\n\n        Color GetClickCircleColor()\n        {\n            if (Args.Button.HasFlag(MouseButtons.Right))\n            {\n                return _settings.RightClickColor;\n            }\n\n            if (Args.Button.HasFlag(MouseButtons.Middle))\n            {\n                return _settings.MiddleClickColor;\n            }\n\n            return _settings.Color;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/Steps/MouseDragBeginStep.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.MouseKeyHook.Steps\n{\n    class MouseDragBeginStep : KeyModifiedStep\n    {\n        readonly Point _start;\n        Point _end;\n        readonly MouseClickSettings _settings;\n\n        const int DragBeginLength = 50;\n\n        public MouseDragBeginStep(Point StartPoint,\n            MouseClickSettings Settings,\n            KeystrokesSettings KeystrokesSettings,\n            KeymapViewModel Keymap) : base(KeystrokesSettings, Keymap)\n        {\n            _start = StartPoint;\n            _settings = Settings;\n        }\n\n        public override void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform)\n        {\n            var start = _start;\n            var end = _end;\n\n            if (PointTransform != null)\n            {\n                start = PointTransform(start);\n                end = PointTransform(end);\n            }\n\n            Editor.DrawArrow(start, end, _settings.Color, _settings.Radius);\n\n            base.Draw(Editor, PointTransform);\n        }\n\n        public override bool Merge(IRecordStep NextStep)\n        {\n            if (NextStep is MouseDragStep mouseDragStep)\n            {\n                mouseDragStep.StartPoint = _start;\n                _end = mouseDragStep.EndPoint;\n\n                var diffX = (_end.X - _start.X);\n                var diffY = (_end.Y - _start.Y);\n\n                var mag = Math.Sqrt(diffX * diffX + diffY * diffY);\n\n                _end = new Point((int)(_start.X + diffX * DragBeginLength / mag),\n                    (int)(_start.Y + diffY * DragBeginLength / mag));\n\n                return false;\n            }\n            else if (NextStep is MouseClickStep)\n            {\n                return true;\n            }\n\n            return base.Merge(NextStep);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.MouseKeyHook/Steps/MouseDragStep.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.MouseKeyHook.Steps\n{\n    class MouseDragStep : KeyModifiedStep\n    {\n        readonly MouseClickSettings _settings;\n\n        public Point StartPoint { get; set; }\n        public Point EndPoint { get; }\n\n        public MouseDragStep(Point EndPoint,\n            MouseClickSettings Settings,\n            KeystrokesSettings KeystrokesSettings,\n            KeymapViewModel Keymap) : base(KeystrokesSettings, Keymap)\n        {\n            this.EndPoint = EndPoint;\n            _settings = Settings;\n        }\n\n        public override void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform)\n        {\n            var start = StartPoint;\n            var end = EndPoint;\n\n            if (PointTransform != null)\n            {\n                start = PointTransform(start);\n                end = PointTransform(end);\n            }\n\n            Editor.DrawArrow(start, end, _settings.Color, _settings.Radius);\n\n            base.Draw(Editor, PointTransform);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.MouseKeyHook/Steps/ScrollStep.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Windows.Forms;\n\nnamespace Captura.MouseKeyHook.Steps\n{\n    class ScrollStep : KeyModifiedStep\n    {\n        public MouseEventArgs Args { get; }\n\n        readonly MouseClickSettings _settings;\n\n        public ScrollStep(MouseEventArgs Args,\n            MouseClickSettings Settings,\n            KeystrokesSettings KeystrokesSettings,\n            KeymapViewModel Keymap) : base(KeystrokesSettings, Keymap)\n        {\n            this.Args = Args;\n\n            _settings = Settings;\n        }\n\n        public override void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform)\n        {\n            var p = Args.Location;\n\n            var r = _settings.Radius;\n            var d = 2 * r;\n\n            Editor.FillEllipse(_settings.Color, new RectangleF(p.X - r, p.Y - r, d, d));\n\n            var above = new Point(p.X, p.Y + r / 2);\n            var below = new Point(p.X, p.Y - r / 2);\n\n            if (Args.Delta < 0)\n            {\n                (above, below) = (below, above);\n            }\n\n            Editor.DrawArrow(above, below, _settings.BorderColor, r / 4f);\n\n            base.Draw(Editor, PointTransform);\n        }\n\n        public override bool Merge(IRecordStep NextStep)\n        {\n            if (NextStep is ScrollStep nextStep)\n            {\n                // Scroll in same direction\n                if (Math.Sign(Args.Delta) == Math.Sign(nextStep.Args.Delta))\n                {\n                    return true;\n                }\n            }\n\n            return base.Merge(NextStep);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.MouseKeyHook/Steps/StepsRecorder.cs",
    "content": "﻿using System;\nusing System.Reactive;\nusing System.Reactive.Linq;\nusing System.Reactive.Subjects;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Captura.Video;\n\nnamespace Captura.MouseKeyHook.Steps\n{\n    public class StepsRecorder : IRecorder\n    {\n        readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();\n        readonly IMouseKeyHook _hook;\n        IVideoFileWriter _videoWriter;\n        IImageProvider _imageProvider;\n        readonly Task _recordTask;\n        volatile bool _recording;\n        readonly StepsSettings _stepsSettings;\n        readonly MouseClickSettings _mouseClickSettings;\n        readonly KeystrokesSettings _keystrokesSettings;\n        readonly KeymapViewModel _keymap;\n        bool _modifierSingleDown;\n\n        IRecordStep _lastStep;\n\n        IObservable<IRecordStep> Observe(IMouseKeyHook Hook, CancellationToken CancellationToken, out IObservable<Unit> ShotObservable)\n        {\n            var subject = new Subject<IRecordStep>();\n            var shotSubject = new Subject<Unit>();\n            ShotObservable = shotSubject;\n\n            void OnNext(IRecordStep NextStep)\n            {\n                if (_lastStep != null)\n                {\n                    if (_lastStep.Merge(NextStep))\n                        return;\n\n                    subject.OnNext(_lastStep);\n                }\n\n                shotSubject.OnNext(Unit.Default);\n\n                _lastStep = NextStep;\n            }\n\n            Hook.MouseClick += (S, E) =>\n            {\n                var step = new MouseClickStep(_mouseClickSettings,\n                    _keystrokesSettings, E,\n                    _keymap);\n\n                OnNext(step);\n            };\n\n            Hook.MouseDoubleClick += (S, E) =>\n            {\n                var step = new MouseClickStep(_mouseClickSettings,\n                    _keystrokesSettings, E,\n                    _keymap);\n\n                OnNext(step);\n            };\n\n            Hook.MouseDragStarted += (S, E) => \n            {\n                var step = new MouseDragBeginStep(E.Location,\n                    _mouseClickSettings,\n                    _keystrokesSettings,\n                    _keymap);\n\n                OnNext(step);\n            };\n\n            Hook.MouseDragFinished += (S, E) =>\n            {\n                var step = new MouseDragStep(E.Location,\n                    _mouseClickSettings,\n                    _keystrokesSettings,\n                    _keymap);\n\n                OnNext(step);\n            };\n\n            if (_stepsSettings.IncludeScrolls)\n            {\n                // TODO: Event is not firing for touchpad scroll\n                Hook.MouseWheel += (S, E) =>\n                {\n                    var step = new ScrollStep(E,\n                        _mouseClickSettings,\n                        _keystrokesSettings,\n                        _keymap);\n\n                    OnNext(step);\n                };\n            }\n\n            Hook.KeyDown += (S, E) =>\n            {\n                _modifierSingleDown = false;\n\n                var record = new KeyRecord(E, _keymap);\n\n                var display = record.Display;\n\n                if (display == _keymap.Control\n                    || display == _keymap.Alt\n                    || display == _keymap.Shift)\n                {\n                    _modifierSingleDown = true;\n                }\n                else OnNext(new KeyStep(_keystrokesSettings, record));\n            };\n\n            Hook.KeyUp += (S, E) =>\n            {\n                var record = new KeyRecord(E, _keymap);\n\n                var display = record.Display;\n\n                if (display == _keymap.Control\n                    || display == _keymap.Alt\n                    || display == _keymap.Shift)\n                {\n                    if (_modifierSingleDown)\n                    {\n                        OnNext(new KeyStep(_keystrokesSettings, record));\n                    }\n                }\n            };\n\n            CancellationToken.Register(() =>\n            {\n                shotSubject.OnCompleted();\n\n                subject.OnNext(_lastStep);\n\n                subject.OnCompleted();\n            });\n\n            return subject\n                .Where(M => _recording);\n        }\n\n        public StepsRecorder(IMouseKeyHook Hook,\n            IVideoFileWriter VideoWriter,\n            IImageProvider ImageProvider,\n            MouseClickSettings MouseClickSettings,\n            KeystrokesSettings KeystrokesSettings,\n            StepsSettings StepsSettings,\n            KeymapViewModel KeymapViewModel)\n        {\n            _hook = Hook;\n            _videoWriter = VideoWriter;\n            _imageProvider = ImageProvider;\n            _stepsSettings = StepsSettings;\n            _mouseClickSettings = MouseClickSettings;\n            _keystrokesSettings = KeystrokesSettings;\n            _keymap = KeymapViewModel;\n\n            var stepsObservable = Observe(_hook, _cancellationTokenSource.Token, out var shotObservable);\n\n            _recordTask = Task.Factory.StartNew(() => DoRecord(stepsObservable, shotObservable), TaskCreationOptions.LongRunning);\n        }\n\n        void DoRecord(IObservable<IRecordStep> StepsObservable, IObservable<Unit> ShotObservable)\n        {\n            var frames = ShotObservable.Select(M => _imageProvider.Capture())\n                .Zip(StepsObservable, (Frame, Step) =>\n                {\n                    Step.Draw(Frame, _imageProvider.PointTransform);\n\n                    return Frame.GenerateFrame(TimeSpan.Zero);\n                });\n\n            foreach (var frame in frames.ToEnumerable())\n            {\n                _videoWriter.WriteFrame(frame);\n            }\n        }\n\n        public void Start() => _recording = true;\n\n        public void Stop() => _recording = false;\n\n        public event Action<Exception> ErrorOccurred;\n\n        public void Dispose()\n        {\n            _recording = false;\n\n            _hook.Dispose();\n            _cancellationTokenSource.Cancel();\n\n            _recordTask.Wait();\n\n            _videoWriter.Dispose();\n            _videoWriter = null;\n\n            _imageProvider?.Dispose();\n            _imageProvider = null;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/keymaps/de.json",
    "content": "{\n  \"$schema\": \"./schema.json\",\n  \"Name\": \"Deutsch (Deutschland)\",\n  \"Mappings\": [\n    {\n      \"On\": [{ }],\n      \"Keys\": {\n        \"Control\": \"Ctrl\",\n        \"ControlKey\": \"Ctrl\",\n        \"LControlKey\": \"Ctrl\",\n        \"RControlKey\": \"Ctrl\",\n\n        \"Alt\": \"Alt\",\n        \"Menu\": \"Alt\",\n        \"LMenu\": \"Alt\",\n        \"RMenu\": \"Alt\",\n\n        \"Shift\": \"Shift\",\n        \"ShiftKey\": \"Shift\",\n        \"LShiftKey\": \"Shift\",\n        \"RShiftKey\": \"Shift\",\n\n        \"LWin\": \"Win\",\n        \"RWin\": \"Win\",\n\n        \"D0\": \"0\",\n        \"D1\": \"1\",\n        \"D2\": \"2\",\n        \"D3\": \"3\",\n        \"D4\": \"4\",\n        \"D5\": \"5\",\n        \"D6\": \"6\",\n        \"D7\": \"7\",\n        \"D8\": \"8\",\n        \"D9\": \"9\",\n\n        \"NumPad0\": \"0\",\n        \"NumPad1\": \"1\",\n        \"NumPad2\": \"2\",\n        \"NumPad3\": \"3\",\n        \"NumPad4\": \"4\",\n        \"NumPad5\": \"5\",\n        \"NumPad6\": \"6\",\n        \"NumPad7\": \"7\",\n        \"NumPad8\": \"8\",\n        \"NumPad9\": \"9\",\n\n        \"Escape\": \"Esc\",\n        \"Back\": \"Backspace\",\n\n        \"PageUp\": \"Pg Up\",\n        \"PageDown\": \"Pg Dn\",\n\n        \"Left\": \"Left\",\n        \"Right\": \"Right\",\n        \"Up\": \"Up\",\n        \"Down\": \"Down\",\n\n        \"PrintScreen\": \"Prt Sc\",\n        \"Insert\": \"Ins\",\n        \"Delete\": \"Del\",\n\n        \"VolumeDown\": \"Vol -\",\n        \"VolumeUp\": \"Vol +\",\n        \"VolumeMute\": \"Mute\",\n\n        \"BrowserBack\": \"Browser Back\",\n        \"BrowserForward\": \"Browser Forward\",\n        \"BrowserRefresh\": \"Browser Refresh\",\n        \"BrowserStop\": \"Browser Stop\",\n        \"BrowserSearch\": \"Browser Search\",\n        \"BrowserFavorites\": \"Browser Favourites\",\n        \"BrowserHome\": \"Browser Home\",\n\n        \"MediaNextTrack\": \"Next Track\",\n        \"MediaPreviousTrack\": \"Prev Track\",\n        \"MediaStop\": \"Stop\",\n        \"MediaPlayPause\": \"Play / Pause\",\n        \"SelectMedia\": \"Select Media\",\n\n        \"LaunchMail\": \"Launch Mail\",\n\n        \"Multiply\": \"*\",\n        \"Add\": \"+\",\n        \"Subtract\": \"-\",\n        \"Divide\": \"/\",\n        \"Decimal\": \".\"  ,\n        \"NumLock\": \"NumLock\",\n\n        \"Oemtilde\": \"ö\",\n        \"OemMinus\": \"-\",\n        \"Oemplus\": \"+\",\n        \"OemCloseBrackets\": \"]\",\n        \"OemOpenBrackets\": \"ß\",\n        \"OemPipe\": \"^\",\n        \"OemPeriod\": \".\",\n        \"Oemcomma\": \",\",\n        \"Oem102\": \"<\",\n        \"Oem2\": \"#\",\n        \"Oem6\": \"´\",\n        \"Oem7\": \"ä\",\n        \"Oem1\": \"ü\"\n      }\n    },\n    {\n      \"On\": [{ \"Shift\": true }],\n      \"Keys\": {\n        \"OemOpenBrackets\": \"?\",\n        \"Oem6\": \"`\",\n        \"Oem2\": \"'\",\n        \"OemPipe\": \"°\",\n        \"D0\": \"=\",\n        \"D1\": \"!\",\n        \"D2\": \"\\\"\",\n        \"D3\": \"§\",\n        \"D4\": \"$\",\n        \"D5\": \"%\",\n        \"D6\": \"&\",\n        \"D7\": \"/\",\n        \"D8\": \"(\",\n        \"D9\": \")\",\n\n        \"Oemtilde\": \"Ö\",\n        \"OemMinus\": \"_\",\n        \"OemQuotes\": \"\\\"\",\n        \"OemSemicolon\": \":\",\n        \"OemPeriod\": \":\",\n        \"Oemcomma\": \";\",\n        \"Oem102\": \">\",\n        \"Oemplus\": \"*\",\n        \"Oem7\": \"Ä\",\n        \"Oem1\": \"Ü\"\n      }\n    },\n    {\n      \"On\": [{ \"Control\": true, \"Alt\": true }],\n      \"Keys\": {\n        \"Oem102\": \"|\",\n        \"Oemplus\": \"~\",\n        \"D7\": \"{\",\n        \"D8\": \"[\",\n        \"D9\": \"]\",\n        \"D0\": \"}\",\n        \"Q\": \"@\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Shift\": true },\n        { \"CapsLock\": true }\n      ],\n      \"Keys\": {\n        \"A\": \"A\",\n        \"B\": \"B\",\n        \"C\": \"C\",\n        \"D\": \"D\",\n        \"E\": \"E\",\n        \"F\": \"F\",\n        \"G\": \"G\",\n        \"H\": \"H\",\n        \"I\": \"I\",\n        \"J\": \"J\",\n        \"K\": \"K\",\n        \"L\": \"L\",\n        \"M\": \"M\",\n        \"N\": \"N\",\n        \"O\": \"O\",\n        \"P\": \"P\",\n        \"Q\": \"Q\",\n        \"R\": \"R\",\n        \"S\": \"S\",\n        \"T\": \"T\",\n        \"U\": \"U\",\n        \"V\": \"V\",\n        \"W\": \"W\",\n        \"X\": \"X\",\n        \"Y\": \"Y\",\n        \"Z\": \"Z\"\n      }\n    },\n    {\n      \"On\": [\n        { },\n        { \"CapsLock\": true, \"Shift\": true }\n      ],\n      \"Keys\": {\n        \"A\": \"a\",\n        \"B\": \"b\",\n        \"C\": \"c\",\n        \"D\": \"d\",\n        \"E\": \"e\",\n        \"F\": \"f\",\n        \"G\": \"g\",\n        \"H\": \"h\",\n        \"I\": \"i\",\n        \"J\": \"j\",\n        \"K\": \"k\",\n        \"L\": \"l\",\n        \"M\": \"m\",\n        \"N\": \"n\",\n        \"O\": \"o\",\n        \"P\": \"p\",\n        \"Q\": \"q\",\n        \"R\": \"r\",\n        \"S\": \"s\",\n        \"T\": \"t\",\n        \"U\": \"u\",\n        \"V\": \"v\",\n        \"W\": \"w\",\n        \"X\": \"x\",\n        \"Y\": \"y\",\n        \"Z\": \"z\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "src/Captura.MouseKeyHook/keymaps/en-IN.json",
    "content": "{\n  \"$schema\": \"./schema.json\",\n  \"Name\": \"English (India)\",\n  \"Mappings\": [\n    {\n      \"On\": [{ }],\n      \"Keys\": {\n        \"Control\": \"Ctrl\",\n        \"ControlKey\": \"Ctrl\",\n        \"LControlKey\": \"Ctrl\",\n        \"RControlKey\": \"Ctrl\",\n\n        \"Alt\": \"Alt\",\n        \"Menu\": \"Alt\",\n        \"LMenu\": \"Alt\",\n        \"RMenu\": \"Alt\",\n        \n        \"Shift\": \"Shift\",\n        \"ShiftKey\": \"Shift\",\n        \"LShiftKey\": \"Shift\",\n        \"RShiftKey\": \"Shift\",\n        \n        \"LWin\": \"Win\",\n        \"RWin\": \"Win\",\n        \n        \"D0\": \"0\",\n        \"D1\": \"1\",\n        \"D2\": \"2\",\n        \"D3\": \"3\",\n        \"D4\": \"4\",\n        \"D5\": \"5\",\n        \"D6\": \"6\",\n        \"D7\": \"7\",\n        \"D8\": \"8\",\n        \"D9\": \"9\",\n        \n        \"NumPad0\": \"0\",\n        \"NumPad1\": \"1\",\n        \"NumPad2\": \"2\",\n        \"NumPad3\": \"3\",\n        \"NumPad4\": \"4\",\n        \"NumPad5\": \"5\",\n        \"NumPad6\": \"6\",\n        \"NumPad7\": \"7\",\n        \"NumPad8\": \"8\",\n        \"NumPad9\": \"9\",\n        \n        \"Escape\": \"Esc\",\n        \"Back\": \"Backspace\",\n        \n        \"PageUp\": \"Pg Up\",\n        \"PageDown\": \"Pg Dn\",\n        \n        \"Left\": \"Left\",\n        \"Right\": \"Right\",\n        \"Up\": \"Up\",\n        \"Down\": \"Down\",\n        \n        \"PrintScreen\": \"Prt Sc\",\n        \"Insert\": \"Ins\",\n        \"Delete\": \"Del\",\n        \n        \"VolumeDown\": \"Vol -\",\n        \"VolumeUp\": \"Vol +\",\n        \"VolumeMute\": \"Mute\",\n        \n        \"BrowserBack\": \"Browser Back\",\n        \"BrowserForward\": \"Browser Forward\",\n        \"BrowserRefresh\": \"Browser Refresh\",\n        \"BrowserStop\": \"Browser Stop\",\n        \"BrowserSearch\": \"Browser Search\",\n        \"BrowserFavorites\": \"Browser Favourites\",\n        \"BrowserHome\": \"Browser Home\",\n        \n        \"MediaNextTrack\": \"Next Track\",\n        \"MediaPreviousTrack\": \"Prev Track\",\n        \"MediaStop\": \"Stop\",\n        \"MediaPlayPause\": \"Play / Pause\",\n        \"SelectMedia\": \"Select Media\",\n        \n        \"LaunchMail\": \"Launch Mail\",\n        \n        \"Multiply\": \"*\",\n        \"Add\": \"+\",\n        \"Subtract\": \"-\",\n        \"Divide\": \"/\",\n        \"Decimal\": \".\",\n        \"NumLock\": \"NumLock\",\n        \n        \"Oemtilde\": \"`\",\n        \"OemMinus\": \"-\",\n        \"Oemplus\": \"=\",\n        \"OemCloseBrackets\": \"]\",\n        \"OemOpenBrackets\": \"[\",\n        \"OemPipe\": \"\\\\\",\n        \"OemQuotes\": \"'\",\n        \"OemSemicolon\": \";\",\n        \"OemPeriod\": \".\",\n        \"Oemcomma\": \",\",\n        \"OemQuestion\": \"/\"\n      }\n    },\n    {\n      \"On\": [{ \"Shift\": true }],\n      \"Keys\": {        \n        \"D0\": \")\",\n        \"D1\": \"!\",\n        \"D2\": \"@\",\n        \"D3\": \"#\",\n        \"D4\": \"$\",\n        \"D5\": \"%\",\n        \"D6\": \"^\",\n        \"D7\": \"&\",\n        \"D8\": \"*\",\n        \"D9\": \"(\",\n        \n        \"Oemtilde\": \"~\",\n        \"OemMinus\": \"_\",\n        \"Oemplus\": \"+\",\n        \"OemCloseBrackets\": \"}\",\n        \"OemOpenBrackets\": \"{\",\n        \"OemPipe\": \"|\",\n        \"OemQuotes\": \"\\\"\",\n        \"OemSemicolon\": \":\",\n        \"OemPeriod\": \">\",\n        \"Oemcomma\": \"<\",\n        \"OemQuestion\": \"?\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Shift\": true },\n        { \"CapsLock\": true }\n      ],\n      \"Keys\": {\n        \"A\": \"A\",\n        \"B\": \"B\",\n        \"C\": \"C\",\n        \"D\": \"D\",\n        \"E\": \"E\",\n        \"F\": \"F\",\n        \"G\": \"G\",\n        \"H\": \"H\",\n        \"I\": \"I\",\n        \"J\": \"J\",\n        \"K\": \"K\",\n        \"L\": \"L\",\n        \"M\": \"M\",\n        \"N\": \"N\",\n        \"O\": \"O\",\n        \"P\": \"P\",\n        \"Q\": \"Q\",\n        \"R\": \"R\",\n        \"S\": \"S\",\n        \"T\": \"T\",\n        \"U\": \"U\",\n        \"V\": \"V\",\n        \"W\": \"W\",\n        \"X\": \"X\",\n        \"Y\": \"Y\",\n        \"Z\": \"Z\"\n      }\n    },\n    {\n      \"On\": [\n        { },\n        { \"CapsLock\": true, \"Shift\": true }\n      ],\n      \"Keys\": {\n        \"A\": \"a\",\n        \"B\": \"b\",\n        \"C\": \"c\",\n        \"D\": \"d\",\n        \"E\": \"e\",\n        \"F\": \"f\",\n        \"G\": \"g\",\n        \"H\": \"h\",\n        \"I\": \"i\",\n        \"J\": \"j\",\n        \"K\": \"k\",\n        \"L\": \"l\",\n        \"M\": \"m\",\n        \"N\": \"n\",\n        \"O\": \"o\",\n        \"P\": \"p\",\n        \"Q\": \"q\",\n        \"R\": \"r\",\n        \"S\": \"s\",\n        \"T\": \"t\",\n        \"U\": \"u\",\n        \"V\": \"v\",\n        \"W\": \"w\",\n        \"X\": \"x\",\n        \"Y\": \"y\",\n        \"Z\": \"z\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Control\": true, \"Shift\": true },\n        { \"Control\": true, \"Alt\": true }\n      ],\n      \"Keys\": {\n        \"D4\": \"₹\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Control\": true, \"Alt\": true },\n        { \"Control\": true, \"Alt\": true, \"Shift\": true, \"CapsLock\": true }\n      ],\n      \"Keys\": {\n        \"Q\": \"æ\",\n        \"E\": \"ē\",\n        \"R\": \"r̥\",\n        \"T\": \"ṭ\",\n        \"Y\": \"ñ\",\n        \"U\": \"ū\",\n        \"I\": \"ī\",\n        \"O\": \"ō\",\n        \"A\": \"ā\",\n        \"S\": \"ś\",\n        \"D\": \"ḍ\",\n        \"G\": \"ṅ\",\n        \"H\": \"ḥ\",\n        \"L\": \"l̥\",\n        \"X\": \"ṣ\",\n        \"N\": \"ṇ\",\n        \"M\": \"ṁ\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Control\": true, \"Alt\": true, \"Shift\": true },\n        { \"Control\": true, \"Alt\": true, \"CapsLock\": true }\n      ],\n      \"Keys\": {\n        \"Q\": \"Æ\",\n        \"E\": \"Ē\",\n        \"R\": \"R̥\",\n        \"T\": \"Ṭ\",\n        \"Y\": \"Ñ\",\n        \"U\": \"Ū\",\n        \"I\": \"Ī\",\n        \"O\": \"Ō\",\n        \"A\": \"Ā\",\n        \"S\": \"Ś\",\n        \"D\": \"Ḍ\",\n        \"G\": \"Ṅ\",\n        \"H\": \"Ḥ\",\n        \"L\": \"L̥\",\n        \"X\": \"Ṣ\",\n        \"N\": \"Ṇ\",\n        \"M\": \"Ṁ\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/keymaps/en.json",
    "content": "{\n  \"$schema\": \"./schema.json\",\n  \"Name\": \"English (United States)\",\n  \"Mappings\": [\n    {\n      \"On\": [{ }],\n      \"Keys\": {\n        \"Control\": \"Ctrl\",\n        \"ControlKey\": \"Ctrl\",\n        \"LControlKey\": \"Ctrl\",\n        \"RControlKey\": \"Ctrl\",\n\n        \"Alt\": \"Alt\",\n        \"Menu\": \"Alt\",\n        \"LMenu\": \"Alt\",\n        \"RMenu\": \"Alt\",\n        \n        \"Shift\": \"Shift\",\n        \"ShiftKey\": \"Shift\",\n        \"LShiftKey\": \"Shift\",\n        \"RShiftKey\": \"Shift\",\n        \n        \"LWin\": \"Win\",\n        \"RWin\": \"Win\",\n        \n        \"D0\": \"0\",\n        \"D1\": \"1\",\n        \"D2\": \"2\",\n        \"D3\": \"3\",\n        \"D4\": \"4\",\n        \"D5\": \"5\",\n        \"D6\": \"6\",\n        \"D7\": \"7\",\n        \"D8\": \"8\",\n        \"D9\": \"9\",\n        \n        \"NumPad0\": \"0\",\n        \"NumPad1\": \"1\",\n        \"NumPad2\": \"2\",\n        \"NumPad3\": \"3\",\n        \"NumPad4\": \"4\",\n        \"NumPad5\": \"5\",\n        \"NumPad6\": \"6\",\n        \"NumPad7\": \"7\",\n        \"NumPad8\": \"8\",\n        \"NumPad9\": \"9\",\n        \n        \"Escape\": \"Esc\",\n        \"Back\": \"Backspace\",\n        \n        \"PageUp\": \"Pg Up\",\n        \"PageDown\": \"Pg Dn\",\n        \n        \"Left\": \"Left\",\n        \"Right\": \"Right\",\n        \"Up\": \"Up\",\n        \"Down\": \"Down\",\n        \n        \"PrintScreen\": \"Prt Sc\",\n        \"Insert\": \"Ins\",\n        \"Delete\": \"Del\",\n        \n        \"VolumeDown\": \"Vol -\",\n        \"VolumeUp\": \"Vol +\",\n        \"VolumeMute\": \"Mute\",\n        \n        \"BrowserBack\": \"Browser Back\",\n        \"BrowserForward\": \"Browser Forward\",\n        \"BrowserRefresh\": \"Browser Refresh\",\n        \"BrowserStop\": \"Browser Stop\",\n        \"BrowserSearch\": \"Browser Search\",\n        \"BrowserFavorites\": \"Browser Favourites\",\n        \"BrowserHome\": \"Browser Home\",\n        \n        \"MediaNextTrack\": \"Next Track\",\n        \"MediaPreviousTrack\": \"Prev Track\",\n        \"MediaStop\": \"Stop\",\n        \"MediaPlayPause\": \"Play / Pause\",\n        \"SelectMedia\": \"Select Media\",\n        \n        \"LaunchMail\": \"Launch Mail\",\n        \n        \"Multiply\": \"*\",\n        \"Add\": \"+\",\n        \"Subtract\": \"-\",\n        \"Divide\": \"/\",\n        \"Decimal\": \".\",\n        \"NumLock\": \"NumLock\",\n        \n        \"Oemtilde\": \"`\",\n        \"OemMinus\": \"-\",\n        \"Oemplus\": \"=\",\n        \"OemCloseBrackets\": \"]\",\n        \"OemOpenBrackets\": \"[\",\n        \"OemPipe\": \"\\\\\",\n        \"OemQuotes\": \"'\",\n        \"OemSemicolon\": \";\",\n        \"OemPeriod\": \".\",\n        \"Oemcomma\": \",\",\n        \"OemQuestion\": \"/\"\n      }\n    },\n    {\n      \"On\": [{ \"Shift\": true }],\n      \"Keys\": {        \n        \"D0\": \")\",\n        \"D1\": \"!\",\n        \"D2\": \"@\",\n        \"D3\": \"#\",\n        \"D4\": \"$\",\n        \"D5\": \"%\",\n        \"D6\": \"^\",\n        \"D7\": \"&\",\n        \"D8\": \"*\",\n        \"D9\": \"(\",\n        \n        \"Oemtilde\": \"~\",\n        \"OemMinus\": \"_\",\n        \"Oemplus\": \"+\",\n        \"OemCloseBrackets\": \"}\",\n        \"OemOpenBrackets\": \"{\",\n        \"OemPipe\": \"|\",\n        \"OemQuotes\": \"\\\"\",\n        \"OemSemicolon\": \":\",\n        \"OemPeriod\": \">\",\n        \"Oemcomma\": \"<\",\n        \"OemQuestion\": \"?\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Shift\": true },\n        { \"CapsLock\": true }\n      ],\n      \"Keys\": {\n        \"A\": \"A\",\n        \"B\": \"B\",\n        \"C\": \"C\",\n        \"D\": \"D\",\n        \"E\": \"E\",\n        \"F\": \"F\",\n        \"G\": \"G\",\n        \"H\": \"H\",\n        \"I\": \"I\",\n        \"J\": \"J\",\n        \"K\": \"K\",\n        \"L\": \"L\",\n        \"M\": \"M\",\n        \"N\": \"N\",\n        \"O\": \"O\",\n        \"P\": \"P\",\n        \"Q\": \"Q\",\n        \"R\": \"R\",\n        \"S\": \"S\",\n        \"T\": \"T\",\n        \"U\": \"U\",\n        \"V\": \"V\",\n        \"W\": \"W\",\n        \"X\": \"X\",\n        \"Y\": \"Y\",\n        \"Z\": \"Z\"\n      }\n    },\n    {\n      \"On\": [\n        { },\n        { \"CapsLock\": true, \"Shift\": true }\n      ],\n      \"Keys\": {\n        \"A\": \"a\",\n        \"B\": \"b\",\n        \"C\": \"c\",\n        \"D\": \"d\",\n        \"E\": \"e\",\n        \"F\": \"f\",\n        \"G\": \"g\",\n        \"H\": \"h\",\n        \"I\": \"i\",\n        \"J\": \"j\",\n        \"K\": \"k\",\n        \"L\": \"l\",\n        \"M\": \"m\",\n        \"N\": \"n\",\n        \"O\": \"o\",\n        \"P\": \"p\",\n        \"Q\": \"q\",\n        \"R\": \"r\",\n        \"S\": \"s\",\n        \"T\": \"t\",\n        \"U\": \"u\",\n        \"V\": \"v\",\n        \"W\": \"w\",\n        \"X\": \"x\",\n        \"Y\": \"y\",\n        \"Z\": \"z\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/keymaps/ml.json",
    "content": "{\n  \"$schema\": \"./schema.json\",\n  \"Name\": \"Malayalam\",\n  \"Mappings\": [\n    {\n      \"On\": [{ }],\n      \"Keys\": {\n        \"Control\": \"Ctrl\",\n        \"ControlKey\": \"Ctrl\",\n        \"LControlKey\": \"Ctrl\",\n        \"RControlKey\": \"Ctrl\",\n\n        \"Alt\": \"Alt\",\n        \"Menu\": \"Alt\",\n        \"LMenu\": \"Alt\",\n        \"RMenu\": \"Alt\",\n        \n        \"Shift\": \"Shift\",\n        \"ShiftKey\": \"Shift\",\n        \"LShiftKey\": \"Shift\",\n        \"RShiftKey\": \"Shift\",\n        \n        \"LWin\": \"Win\",\n        \"RWin\": \"Win\",\n\n        \"A\": \"ോ\",\n        \"B\": \"വ\",\n        \"C\": \"മ\",\n        \"D\": \"്\",\n        \"E\": \"ാ\",\n        \"F\": \"ി\",\n        \"G\": \"ു\",\n        \"H\": \"പ\",\n        \"I\": \"ഗ\",\n        \"J\": \"ര\",\n        \"K\": \"ക\",\n        \"L\": \"ത\",\n        \"M\": \"സ\",\n        \"N\": \"ല\",\n        \"O\": \"ദ\",\n        \"P\": \"ജ\",\n        \"Q\": \"ൌ\",\n        \"R\": \"ീ\",\n        \"S\": \"േ\",\n        \"T\": \"ൂ\",\n        \"U\": \"ഹ\",\n        \"V\": \"ന\",\n        \"W\": \"ൈ\",\n        \"X\": \"ം\",\n        \"Y\": \"ബ\",\n        \"Z\": \"െ\",\n        \n        \"D0\": \"0\",\n        \"D1\": \"1\",\n        \"D2\": \"2\",\n        \"D3\": \"3\",\n        \"D4\": \"4\",\n        \"D5\": \"5\",\n        \"D6\": \"6\",\n        \"D7\": \"7\",\n        \"D8\": \"8\",\n        \"D9\": \"9\",\n        \n        \"NumPad0\": \"0\",\n        \"NumPad1\": \"1\",\n        \"NumPad2\": \"2\",\n        \"NumPad3\": \"3\",\n        \"NumPad4\": \"4\",\n        \"NumPad5\": \"5\",\n        \"NumPad6\": \"6\",\n        \"NumPad7\": \"7\",\n        \"NumPad8\": \"8\",\n        \"NumPad9\": \"9\",\n        \n        \"Escape\": \"Esc\",\n        \"Back\": \"Backspace\",\n        \n        \"PageUp\": \"Pg Up\",\n        \"PageDown\": \"Pg Dn\",\n        \n        \"Left\": \"Left\",\n        \"Right\": \"Right\",\n        \"Up\": \"Up\",\n        \"Down\": \"Down\",\n        \n        \"PrintScreen\": \"Prt Sc\",\n        \"Insert\": \"Ins\",\n        \"Delete\": \"Del\",\n        \n        \"VolumeDown\": \"Vol -\",\n        \"VolumeUp\": \"Vol +\",\n        \"VolumeMute\": \"Mute\",\n        \n        \"BrowserBack\": \"Browser Back\",\n        \"BrowserForward\": \"Browser Forward\",\n        \"BrowserRefresh\": \"Browser Refresh\",\n        \"BrowserStop\": \"Browser Stop\",\n        \"BrowserSearch\": \"Browser Search\",\n        \"BrowserFavorites\": \"Browser Favourites\",\n        \"BrowserHome\": \"Browser Home\",\n        \n        \"MediaNextTrack\": \"Next Track\",\n        \"MediaPreviousTrack\": \"Prev Track\",\n        \"MediaStop\": \"Stop\",\n        \"MediaPlayPause\": \"Play / Pause\",\n        \"SelectMedia\": \"Select Media\",\n        \n        \"LaunchMail\": \"Launch Mail\",\n        \n        \"Multiply\": \"*\",\n        \"Add\": \"+\",\n        \"Subtract\": \"-\",\n        \"Divide\": \"/\",\n        \"Decimal\": \".\",\n        \"NumLock\": \"NumLock\",\n        \n        \"Oemtilde\": \"ൊ\",\n        \"OemMinus\": \"-\",\n        \"Oemplus\": \"ൃ\",\n        \"OemCloseBrackets\": \"ർ\",\n        \"OemOpenBrackets\": \"ഡ\",\n        \"OemQuotes\": \"ട\",\n        \"OemSemicolon\": \"ച\",\n        \"OemPeriod\": \".\",\n        \"Oemcomma\": \",\",\n        \"OemQuestion\": \"യ\"\n      }\n    },\n    {\n      \"On\": [{ \"Control\": true, \"Shift\": true }],\n      \"Keys\": {\n        \"D4\": \"₹\"\n      }\n    },\n    {\n      \"On\": [{ \"Shift\": true }],\n      \"Keys\": {\n        \"A\": \"ഓ\",\n        \"B\": \"ഴ\",\n        \"C\": \"ണ\",\n        \"D\": \"അ\",\n        \"E\": \"ആ\",\n        \"F\": \"ഇ\",\n        \"G\": \"ഉ\",\n        \"H\": \"ഫ\",\n        \"I\": \"ഘ\",\n        \"J\": \"റ\",\n        \"K\": \"ഖ\",\n        \"L\": \"ഥ\",\n        \"M\": \"ശ\",\n        \"N\": \"ള\",\n        \"O\": \"ധ\",\n        \"P\": \"ഝ\",\n        \"Q\": \"ഔ\",\n        \"R\": \"ഈ\",\n        \"S\": \"ഏ\",\n        \"T\": \"ഊ\",\n        \"U\": \"ങ\",\n        \"V\": \"ൻ\",\n        \"W\": \"ഐ\",\n        \"X\": \"ൺ\",\n        \"Y\": \"ഭ\",\n        \"Z\": \"എ\",\n\n        \"D0\": \")\",\n        \"D3\": \"്ര\",\n        \"D6\": \"ൿ\",\n        \"D7\": \"ക്ഷ\",\n        \"D8\": \"ൾ\",\n        \"D9\": \"(\",\n\n        \"Oemtilde\": \"ഒ\",\n        \"OemMinus\": \"ഃ\",\n        \"Oemplus\": \"ഋ\",\n        \"OemCloseBrackets\": \"ഞ\",\n        \"OemOpenBrackets\": \"ഢ\",\n        \"OemQuotes\": \"ഠ\",\n        \"OemSemicolon\": \"ഛ\",\n        \"OemPeriod\": \"ൽ\",\n        \"Oemcomma\": \"ഷ\"\n      }\n    },\n    {\n      \"On\": [{ \"Control\": true, \"Alt\": true }],\n      \"Keys\": {\n        \"D0\": \"൦\",\n        \"D1\": \"൧\",\n        \"D2\": \"൨\",\n        \"D3\": \"൩\",\n        \"D4\": \"൪\",\n        \"D5\": \"൫\",\n        \"D6\": \"൬\",\n        \"D7\": \"൭\",\n        \"D8\": \"൮\",\n        \"D9\": \"൯\",\n\n        \"Q\": \"ൗ\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/keymaps/schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"Name\": {\n      \"type\": \"string\",\n      \"description\": \"Name of the layout. This is displayed in the layout selection menu.\"\n    },\n    \"Mappings\": {\n      \"type\": \"array\",\n      \"description\": \"Mappings grouped by the state of modifier keys and Caps Lock\",\n      \"items\": {\n        \"properties\": {\n          \"On\": {\n            \"type\": \"array\",\n            \"description\": \"Match Any of these conditions\",\n            \"items\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"Shift\": {\n                  \"type\": \"boolean\",\n                  \"description\": \"Is Shift key pressed?\"\n                },\n                \"Alt\": {\n                  \"type\": \"boolean\",\n                  \"description\": \"Is Alt key pressed?\"\n                },\n                \"Control\": {\n                  \"type\": \"boolean\",\n                  \"description\": \"Is Control key pressed?\"\n                },\n                \"CapsLock\": {\n                  \"type\": \"boolean\",\n                  \"description\": \"Is Caps Lock On?\"\n                }\n              },\n              \"additionalProperties\": false\n            },\n            \"minItems\": 1\n          },\n          \"Keys\": {\n            \"type\": \"object\",\n            \"description\": \"Key to text mappings. if no matching mapping is found, name of Key is used.\",\n            \"properties\": {\n              \"LButton\": { \"type\": \"string\" },\n              \"RButton\": { \"type\": \"string\" },\n              \"Cancel\": { \"type\": \"string\" },\n              \"MButton\": { \"type\": \"string\" },\n              \"XButton1\": { \"type\": \"string\" },\n              \"XButton2\": { \"type\": \"string\" },\n              \"Back\": { \"type\": \"string\" },\n              \"Tab\": { \"type\": \"string\" },\n              \"LineFeed\": { \"type\": \"string\" },\n              \"Clear\": { \"type\": \"string\" },\n              \"Return\": { \"type\": \"string\" },\n              \"Enter\": { \"type\": \"string\" },\n              \"ShiftKey\": { \"type\": \"string\" },\n              \"ControlKey\": { \"type\": \"string\" },\n              \"Menu\": { \"type\": \"string\" },\n              \"Pause\": { \"type\": \"string\" },\n              \"Capital\": { \"type\": \"string\" },\n              \"CapsLock\": { \"type\": \"string\" },\n              \"KanaMode\": { \"type\": \"string\" },\n              \"HanguelMode\": { \"type\": \"string\" },\n              \"HangulMode\": { \"type\": \"string\" },\n              \"JunjaMode\": { \"type\": \"string\" },\n              \"FinalMode\": { \"type\": \"string\" },\n              \"HanjaMode\": { \"type\": \"string\" },\n              \"KanjiMode\": { \"type\": \"string\" },\n              \"Escape\": { \"type\": \"string\" },\n              \"IMEConvert\": { \"type\": \"string\" },\n              \"IMENonconvert\": { \"type\": \"string\" },\n              \"IMEAccept\": { \"type\": \"string\" },\n              \"IMEAceept\": { \"type\": \"string\" },\n              \"IMEModeChange\": { \"type\": \"string\" },\n              \"Space\": { \"type\": \"string\" },\n              \"Prior\": { \"type\": \"string\" },\n              \"PageUp\": { \"type\": \"string\" },\n              \"Next\": { \"type\": \"string\" },\n              \"PageDown\": { \"type\": \"string\" },\n              \"End\": { \"type\": \"string\" },\n              \"Home\": { \"type\": \"string\" },\n              \"Left\": { \"type\": \"string\" },\n              \"Up\": { \"type\": \"string\" },\n              \"Right\": { \"type\": \"string\" },\n              \"Down\": { \"type\": \"string\" },\n              \"Select\": { \"type\": \"string\" },\n              \"Print\": { \"type\": \"string\" },\n              \"Execute\": { \"type\": \"string\" },\n              \"Snapshot\": { \"type\": \"string\" },\n              \"PrintScreen\": { \"type\": \"string\" },\n              \"Insert\": { \"type\": \"string\" },\n              \"Delete\": { \"type\": \"string\" },\n              \"Help\": { \"type\": \"string\" },\n              \"D0\": { \"type\": \"string\" },\n              \"D1\": { \"type\": \"string\" },\n              \"D2\": { \"type\": \"string\" },\n              \"D3\": { \"type\": \"string\" },\n              \"D4\": { \"type\": \"string\" },\n              \"D5\": { \"type\": \"string\" },\n              \"D6\": { \"type\": \"string\" },\n              \"D7\": { \"type\": \"string\" },\n              \"D8\": { \"type\": \"string\" },\n              \"D9\": { \"type\": \"string\" },\n              \"A\": { \"type\": \"string\" },\n              \"B\": { \"type\": \"string\" },\n              \"C\": { \"type\": \"string\" },\n              \"D\": { \"type\": \"string\" },\n              \"E\": { \"type\": \"string\" },\n              \"F\": { \"type\": \"string\" },\n              \"G\": { \"type\": \"string\" },\n              \"H\": { \"type\": \"string\" },\n              \"I\": { \"type\": \"string\" },\n              \"J\": { \"type\": \"string\" },\n              \"K\": { \"type\": \"string\" },\n              \"L\": { \"type\": \"string\" },\n              \"M\": { \"type\": \"string\" },\n              \"N\": { \"type\": \"string\" },\n              \"O\": { \"type\": \"string\" },\n              \"P\": { \"type\": \"string\" },\n              \"Q\": { \"type\": \"string\" },\n              \"R\": { \"type\": \"string\" },\n              \"S\": { \"type\": \"string\" },\n              \"T\": { \"type\": \"string\" },\n              \"U\": { \"type\": \"string\" },\n              \"V\": { \"type\": \"string\" },\n              \"W\": { \"type\": \"string\" },\n              \"X\": { \"type\": \"string\" },\n              \"Y\": { \"type\": \"string\" },\n              \"Z\": { \"type\": \"string\" },\n              \"LWin\": { \"type\": \"string\" },\n              \"RWin\": { \"type\": \"string\" },\n              \"Apps\": { \"type\": \"string\" },\n              \"Sleep\": { \"type\": \"string\" },\n              \"NumPad0\": { \"type\": \"string\" },\n              \"NumPad1\": { \"type\": \"string\" },\n              \"NumPad2\": { \"type\": \"string\" },\n              \"NumPad3\": { \"type\": \"string\" },\n              \"NumPad4\": { \"type\": \"string\" },\n              \"NumPad5\": { \"type\": \"string\" },\n              \"NumPad6\": { \"type\": \"string\" },\n              \"NumPad7\": { \"type\": \"string\" },\n              \"NumPad8\": { \"type\": \"string\" },\n              \"NumPad9\": { \"type\": \"string\" },\n              \"Multiply\": { \"type\": \"string\" },\n              \"Add\": { \"type\": \"string\" },\n              \"Separator\": { \"type\": \"string\" },\n              \"Subtract\": { \"type\": \"string\" },\n              \"Decimal\": { \"type\": \"string\" },\n              \"Divide\": { \"type\": \"string\" },\n              \"F1\": { \"type\": \"string\" },\n              \"F2\": { \"type\": \"string\" },\n              \"F3\": { \"type\": \"string\" },\n              \"F4\": { \"type\": \"string\" },\n              \"F5\": { \"type\": \"string\" },\n              \"F6\": { \"type\": \"string\" },\n              \"F7\": { \"type\": \"string\" },\n              \"F8\": { \"type\": \"string\" },\n              \"F9\": { \"type\": \"string\" },\n              \"F10\": { \"type\": \"string\" },\n              \"F11\": { \"type\": \"string\" },\n              \"F12\": { \"type\": \"string\" },\n              \"F13\": { \"type\": \"string\" },\n              \"F14\": { \"type\": \"string\" },\n              \"F15\": { \"type\": \"string\" },\n              \"F16\": { \"type\": \"string\" },\n              \"F17\": { \"type\": \"string\" },\n              \"F18\": { \"type\": \"string\" },\n              \"F19\": { \"type\": \"string\" },\n              \"F20\": { \"type\": \"string\" },\n              \"F21\": { \"type\": \"string\" },\n              \"F22\": { \"type\": \"string\" },\n              \"F23\": { \"type\": \"string\" },\n              \"F24\": { \"type\": \"string\" },\n              \"NumLock\": { \"type\": \"string\" },\n              \"Scroll\": { \"type\": \"string\" },\n              \"LShiftKey\": { \"type\": \"string\" },\n              \"RShiftKey\": { \"type\": \"string\" },\n              \"LControlKey\": { \"type\": \"string\" },\n              \"RControlKey\": { \"type\": \"string\" },\n              \"LMenu\": { \"type\": \"string\" },\n              \"RMenu\": { \"type\": \"string\" },\n              \"BrowserBack\": { \"type\": \"string\" },\n              \"BrowserForward\": { \"type\": \"string\" },\n              \"BrowserRefresh\": { \"type\": \"string\" },\n              \"BrowserStop\": { \"type\": \"string\" },\n              \"BrowserSearch\": { \"type\": \"string\" },\n              \"BrowserFavorites\": { \"type\": \"string\" },\n              \"BrowserHome\": { \"type\": \"string\" },\n              \"VolumeMute\": { \"type\": \"string\" },\n              \"VolumeDown\": { \"type\": \"string\" },\n              \"VolumeUp\": { \"type\": \"string\" },\n              \"MediaNextTrack\": { \"type\": \"string\" },\n              \"MediaPreviousTrack\": { \"type\": \"string\" },\n              \"MediaStop\": { \"type\": \"string\" },\n              \"MediaPlayPause\": { \"type\": \"string\" },\n              \"LaunchMail\": { \"type\": \"string\" },\n              \"SelectMedia\": { \"type\": \"string\" },\n              \"LaunchApplication1\": { \"type\": \"string\" },\n              \"LaunchApplication2\": { \"type\": \"string\" },\n              \"OemSemicolon\": { \"type\": \"string\" },\n              \"Oem1\": { \"type\": \"string\" },\n              \"Oemplus\": { \"type\": \"string\" },\n              \"Oemcomma\": { \"type\": \"string\" },\n              \"OemMinus\": { \"type\": \"string\" },\n              \"OemPeriod\": { \"type\": \"string\" },\n              \"OemQuestion\": { \"type\": \"string\" },\n              \"Oem2\": { \"type\": \"string\" },\n              \"Oemtilde\": { \"type\": \"string\" },\n              \"Oem3\": { \"type\": \"string\" },\n              \"OemOpenBrackets\": { \"type\": \"string\" },\n              \"Oem4\": { \"type\": \"string\" },\n              \"OemPipe\": { \"type\": \"string\" },\n              \"Oem5\": { \"type\": \"string\" },\n              \"OemCloseBrackets\": { \"type\": \"string\" },\n              \"Oem6\": { \"type\": \"string\" },\n              \"OemQuotes\": { \"type\": \"string\" },\n              \"Oem7\": { \"type\": \"string\" },\n              \"Oem8\": { \"type\": \"string\" },\n              \"OemBackslash\": { \"type\": \"string\" },\n              \"Oem102\": { \"type\": \"string\" },\n              \"ProcessKey\": { \"type\": \"string\" },\n              \"Packet\": { \"type\": \"string\" },\n              \"Attn\": { \"type\": \"string\" },\n              \"Crsel\": { \"type\": \"string\" },\n              \"Exsel\": { \"type\": \"string\" },\n              \"EraseEof\": { \"type\": \"string\" },\n              \"Play\": { \"type\": \"string\" },\n              \"Zoom\": { \"type\": \"string\" },\n              \"NoName\": { \"type\": \"string\" },\n              \"Pa1\": { \"type\": \"string\" },\n              \"OemClear\": { \"type\": \"string\" },\n              \"Shift\": { \"type\": \"string\" },\n              \"Control\": { \"type\": \"string\" },\n              \"Alt\": { \"type\": \"string\" }\n            },\n            \"additionalProperties\": false\n          }\n        },\n        \"additionalProperties\": false,\n        \"required\": [\"Keys\", \"On\"]\n      }\n    }\n  },\n  \"required\": [\"Name\", \"Mappings\"]\n}"
  },
  {
    "path": "src/Captura.MouseKeyHook/keymaps/tr.json",
    "content": "{\n  \"$schema\": \"./schema.json\",\n  \"Name\": \"Türkçe-Q (Turkey)\",\n  \"Mappings\": [\n    {\n      \"On\": [{ }],\n      \"Keys\": {\n        \"Control\": \"Ctrl\",\n        \"ControlKey\": \"Ctrl\",\n        \"LControlKey\": \"LCtrl\",\n        \"RControlKey\": \"RCtrl\",\n        \"Alt\": \"Alt\",\n        \"Menu\": \"Alt\",\n        \"LMenu\": \"Alt\",\n        \"RMenu\": \"Alt\",\n        \"Shift\": \"Shift\",\n        \"ShiftKey\": \"Shift\",\n        \"LShiftKey\": \"Shift\",\n        \"RShiftKey\": \"Shift\",\n        \"LWin\": \"LWin\",\n        \"RWin\": \"RWin\",\n        \"Capital\": \"CapsLock\",\n        \"D0\": \"0\",\n        \"D1\": \"1\",\n        \"D2\": \"2\",\n        \"D3\": \"3\",\n        \"D4\": \"4\",\n        \"D5\": \"5\",\n        \"D6\": \"6\",\n        \"D7\": \"7\",\n        \"D8\": \"8\",\n        \"D9\": \"9\",\n        \"NumPad0\": \"0\",\n        \"NumPad1\": \"1\",\n        \"NumPad2\": \"2\",\n        \"NumPad3\": \"3\",\n        \"NumPad4\": \"4\",\n        \"NumPad5\": \"5\",\n        \"NumPad6\": \"6\",\n        \"NumPad7\": \"7\",\n        \"NumPad8\": \"8\",\n        \"NumPad9\": \"9\",\n        \n        \"Escape\": \"Esc\",\n        \"Back\": \"Backspace\",\n        \"PageUp\": \"PgUp\",\n        \"PageDown\": \"PgDn\",\n        \"PrintScreen\": \"PrtScn\",\n        \"Insert\": \"Ins\",\n        \"VolumeDown\": \"Ses -\",\n        \"VolumeUp\": \"Ses +\",\n        \"VolumeMute\": \"Sessiz\",\n        \"BrowserBack\": \"Tarayıcı Geri\",\n        \"BrowserForward\": \"Tarayıcı İleri\",\n        \"BrowserRefresh\": \"Tarayıcı Yenile\",\n        \"BrowserStop\": \"Tarayıcı Dur\",\n        \"BrowserSearch\": \"Tarayıcı Ara\",\n        \"BrowserFavorites\": \"Tarayıcı Favoriler\",\n        \"BrowserHome\": \"Tarayıcı Ana sayfa\",\n        \"MediaNextTrack\": \"Sonraki Parça\",\n        \"MediaPreviousTrack\": \"Önceki Parça\",\n        \"MediaStop\": \"Dur\",\n        \"MediaPlayPause\": \"Oynat / Durakla\",\n        \"SelectMedia\": \"Medya seç\",\n        \"LaunchMail\": \"Posta çalıştır\",\n        \"NumLock\": \"NumLock\",\n        \"Oemtilde\": \"\\\"\",\n        \"OemMinus\": \"-\",\n        \"Oemplus\": \"=\",\n        \"OemCloseBrackets\": \"ü\",\n        \"OemOpenBrackets\": \"ğ\",\n        \"OemPipe\": \"ç\",\n        \"OemQuotes\": \"i\",\n        \"OemSemicolon\": \"ş\",\n        \"OemPeriod\": \".\",\n        \"Oemcomma\": \",\",\n        \"OemQuestion\": \"ö\",\n        \"Oem8\": \"*\",\n        \"OemBackslash\": \"<\"\n      }\n    },\n    {\n      \"On\": [\n        { },\n        { \"CapsLock\": true }\n      ],\n      \"Keys\": {\n        \"Return\": \"ENTER\",\n        \"Space\": \"Boşluk\",\n        \"Left\": \"Sola\",\n        \"Right\": \"Sağa\",\n        \"Up\": \"Yukarı\",\n        \"Down\": \"Aşağı\",\n        \"Decimal\": \",\",\n        \"Multiply\": \"*\",\n        \"Add\": \"+\",\n        \"Subtract\": \"-\",\n        \"Divide\": \"/\",\n        \"Oemtilde\": \"\\\"\",\n        \"Delete\": \"Del\",\n        \"Capital\": \"CapsLock\"\n      }\n    },\n    {\n      \"On\": [{ \"Shift\": true }],\n      \"Keys\": {\n        \"D0\": \"=\",\n        \"D1\": \"!\",\n        \"D2\": \"'\",\n        \"D3\": \"^\",\n        \"D4\": \"+\",\n        \"D5\": \"%\",\n        \"D6\": \"&\",\n        \"D7\": \"/\",\n        \"D8\": \"(\",\n        \"D9\": \")\",\n        \"OemMinus\": \"_\",\n        \"Oemplus\": \"+\",\n        \"OemCloseBrackets\": \"Ü\",\n        \"OemOpenBrackets\": \"Ğ\",\n        \"OemPipe\": \"Ç\",\n        \"OemQuotes\": \"İ\",\n        \"OemSemicolon\": \"Ş\",\n        \"OemPeriod\": \":\",\n        \"Oemcomma\": \";\",\n        \"OemQuestion\": \"Ö\",\n        \"Oem8\": \"?\",\n        \"Oemtilde\": \"é\",\n        \"OemBackslash\": \">\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Shift\": true },\n        { \"CapsLock\": true }\n      ],\n      \"Keys\": {\n        \"A\": \"A\",\n        \"B\": \"B\",\n        \"C\": \"C\",\n        \"D\": \"D\",\n        \"E\": \"E\",\n        \"F\": \"F\",\n        \"G\": \"G\",\n        \"H\": \"H\",\n        \"I\": \"I\",\n        \"J\": \"J\",\n        \"K\": \"K\",\n        \"L\": \"L\",\n        \"M\": \"M\",\n        \"N\": \"N\",\n        \"O\": \"O\",\n        \"P\": \"P\",\n        \"Q\": \"Q\",\n        \"R\": \"R\",\n        \"S\": \"S\",\n        \"T\": \"T\",\n        \"U\": \"U\",\n        \"V\": \"V\",\n        \"W\": \"W\",\n        \"X\": \"X\",\n        \"Y\": \"Y\",\n        \"Z\": \"Z\",\n\n        \"D1\": \"1\",\n        \"D2\": \"2\",\n        \"D3\": \"3\",\n        \"D4\": \"4\",\n        \"D5\": \"5\",\n        \"D6\": \"6\",\n        \"D7\": \"7\",\n        \"D8\": \"8\",\n        \"D9\": \"9\",\n        \"D0\": \"0\",\n        \"Oem8\": \"*\",\n        \"OemMinus\": \"-\",\n        \"OemOpenBrackets\": \"Ğ\",\n        \"Oem6\": \"Ü\",\n        \"Oem1\": \"Ş\",\n        \"Oem7\": \"İ\",\n        \"Oemcomma\": \",\",\n        \"OemBackslash\": \"<\",\n        \"OemQuestion\": \"Ö\",\n        \"Oem5\": \"Ç\",\n        \"OemPeriod\": \".\"\n      }\n    },\n    {\n      \"On\": [\n        { },\n        { \"CapsLock\": true, \"Shift\": true }\n      ],\n      \"Keys\": {\n        \"A\": \"a\",\n        \"B\": \"b\",\n        \"C\": \"c\",\n        \"D\": \"d\",\n        \"E\": \"e\",\n        \"F\": \"f\",\n        \"G\": \"g\",\n        \"H\": \"h\",\n        \"I\": \"ı\",\n        \"J\": \"j\",\n        \"K\": \"k\",\n        \"L\": \"l\",\n        \"M\": \"m\",\n        \"N\": \"n\",\n        \"O\": \"o\",\n        \"P\": \"p\",\n        \"Q\": \"q\",\n        \"R\": \"r\",\n        \"S\": \"s\",\n        \"T\": \"t\",\n        \"U\": \"u\",\n        \"V\": \"v\",\n        \"W\": \"w\",\n        \"X\": \"x\",\n        \"Y\": \"y\",\n        \"Z\": \"z\",\n        \"D1\": \"!\",\n        \"D2\": \"'\",\n        \"D3\": \"^\",\n        \"D4\": \"+\",\n        \"D5\": \"%\",\n        \"D6\": \"&\",\n        \"D7\": \"/\",\n        \"D8\": \"(\",\n        \"D9\": \")\",\n        \"D0\": \"=\",\n        \"Oem8\": \"?\",\n        \"OemMinus\": \"_\",\n        \"OemOpenBrackets\": \"ğ\",\n        \"Oem6\": \"ü\",\n        \"Oem1\": \"ş\",\n        \"Oem7\": \"i\",\n        \"Oemcomma\": \";\",\n        \"OemBackslash\": \">\",\n        \"OemQuestion\": \"ö\",\n        \"Oem5\": \"ç\",\n        \"OemPeriod\": \":\",\n        \"Oemtilde\": \"é\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Control\": true, \"Alt\": true },\n        { \"CapsLock\": true, \"Control\": true, \"Alt\": true }\n      ],\n      \"Keys\": {\n        \"E\": \"€\",\n        \"Q\": \"@\",\n        \"S\": \"ß\",\n        \"T\": \"₺\",\n        \"Oemtilde\": \"<\",\n        \"D1\": \">\",\n        \"D2\": \"£\",\n        \"D3\": \"#\",\n        \"D4\": \"$\",\n        \"D5\": \"½\",\n        \"D7\": \"{\",\n        \"D8\": \"[\",\n        \"D9\": \"]\",\n        \"D0\": \"}\",\n        \"Oem8\": \"\\\\\",\n        \"OemMinus\": \"|\",\n        \"OemOpenBrackets\": \"¨\",\n        \"Oem6\": \"~\",\n        \"Oem1\": \"´\",\n        \"Oemcomma\": \"`\",\n        \"OemBackslash\": \"|\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Control\": true, \"Alt\": true },\n        { \"CapsLock\": true, \"Control\": true, \"Alt\": true, \"Shift\": true }\n      ],\n      \"Keys\": {\n        \"I\": \"i\",\n        \"A\": \"æ\"\n      }\n    },\n    {\n      \"On\": [\n        { \"Control\": true, \"Alt\": true, \"Shift\": true },\n        { \"CapsLock\": true, \"Control\": true, \"Alt\": true }\n      ],\n      \"Keys\": {\n        \"I\": \"İ\",\n        \"A\": \"Æ\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "src/Captura.NAudio/Captura.NAudio.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageReference Include=\"NAudio\" Version=\"1.10.0\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Audio\\Captura.Audio.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Captura.NAudio/MixedAudioProvider.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing NAudio.Wave;\nusing NAudio.Wave.SampleProviders;\n\nnamespace Captura.Audio\n{\n    class MixedAudioProvider : IAudioProvider\n    {\n        readonly Dictionary<NAudioProvider, ISampleProvider> _audioProviders = new Dictionary<NAudioProvider, ISampleProvider>();\n\n        readonly IWaveProvider _mixingWaveProvider;\n\n        public MixedAudioProvider(params NAudioProvider[] AudioProviders)\n        {\n            foreach (var provider in AudioProviders)\n            {\n                var bufferedProvider = new BufferedWaveProvider(provider.NAudioWaveFormat)\n                {\n                    DiscardOnBufferOverflow = true,\n                    ReadFully = false\n                };\n\n                provider.WaveIn.DataAvailable += (S, E) =>\n                {\n                    bufferedProvider.AddSamples(E.Buffer, 0, E.BytesRecorded);\n                };\n\n                var sampleProvider = bufferedProvider.ToSampleProvider();\n\n                var providerWf = provider.WaveFormat;\n\n                // Mono to Stereo\n                if (providerWf.Channels == 1)\n                    sampleProvider = sampleProvider.ToStereo();\n\n                // Resample\n                if (providerWf.SampleRate != WaveFormat.SampleRate)\n                {\n                    sampleProvider = new WdlResamplingSampleProvider(sampleProvider, WaveFormat.SampleRate);\n                }\n\n                _audioProviders.Add(provider, sampleProvider);\n            }\n\n            if (_audioProviders.Count == 1)\n            {\n                _mixingWaveProvider = _audioProviders\n                    .Values\n                    .First()\n                    .ToWaveProvider16();\n            }\n            else\n            {\n                var waveProviders = _audioProviders.Values.Select(M => M.ToWaveProvider());\n\n                // MixingSampleProvider cannot be used here due to it removing inputs that don't return as many bytes as requested.\n\n                // Screna expects 44.1 kHz 16-bit Stereo\n                _mixingWaveProvider = new MixingWaveProvider32(waveProviders)\n                    .ToSampleProvider()\n                    .ToWaveProvider16();\n            }\n        }\n\n        public void Dispose()\n        {\n            foreach (var provider in _audioProviders.Keys)\n            {\n                provider.Dispose();\n            }\n        }\n\n        public WaveFormat WaveFormat { get; } = new WaveFormat();\n\n        public void Start()\n        {\n            foreach (var provider in _audioProviders.Keys)\n            {\n                provider.Start();\n            }\n        }\n\n        public void Stop()\n        {\n            foreach (var provider in _audioProviders.Keys)\n            {\n                provider.Stop();\n            }\n        }\n\n        public int Read(byte[] Buffer, int Offset, int Length)\n        {\n            return _mixingWaveProvider.Read(Buffer, Offset, Length);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.NAudio/NAudioItem.cs",
    "content": "﻿using System;\nusing NAudio.CoreAudioApi;\nusing NAudio.Wave;\n\nnamespace Captura.Audio\n{\n    class NAudioItem : IAudioItem\n    {\n        public MMDevice Device { get; }\n\n        public bool IsLoopback { get; }\n\n        AudioClient _audioClient;\n\n        public void StartListeningForPeakLevel()\n        {\n            if (_audioClient != null)\n                return;\n\n            // Peak Level is available for recording devices only when they are active\n            if (IsLoopback)\n                return;\n\n            _audioClient = Device.AudioClient;\n            _audioClient.Initialize(AudioClientShareMode.Shared,\n                AudioClientStreamFlags.None,\n                100,\n                100,\n                _audioClient.MixFormat,\n                Guid.Empty);\n\n            _audioClient.Start();\n        }\n\n        public void StopListeningForPeakLevel()\n        {\n            if (_audioClient == null)\n                return;\n\n            _audioClient.Stop();\n            _audioClient.Dispose();\n            _audioClient = null;\n\n            _audioClient = null;\n        }\n\n        public string Name { get; }\n\n        public NAudioItem(MMDevice Device, bool IsLoopback)\n            : this(Device, Device.FriendlyName, IsLoopback)\n        {\n        }\n\n        NAudioItem(MMDevice Device, string Name, bool IsLoopback)\n        {\n            this.Device = Device;\n            this.IsLoopback = IsLoopback;\n            this.Name = Name;\n        }\n\n        const string DefaultDeviceName = \"Default\";\n\n        public static NAudioItem DefaultMicrophone => new NAudioItem(\n            WasapiCapture.GetDefaultCaptureDevice(),\n            DefaultDeviceName,\n            false);\n\n        public static NAudioItem DefaultSpeaker => new NAudioItem(\n            WasapiLoopbackCapture.GetDefaultLoopbackCaptureDevice(),\n            DefaultDeviceName,\n            true);\n\n        public double PeakLevel => Device.AudioMeterInformation.MasterPeakValue;\n\n        public override string ToString() => Name;\n        \n        public void Dispose()\n        {\n            StopListeningForPeakLevel();\n\n            // Not disposing the device as it may be in use in a recording.\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.NAudio/NAudioNotificationClient.cs",
    "content": "﻿using System;\nusing NAudio.CoreAudioApi;\nusing NAudio.CoreAudioApi.Interfaces;\n\nnamespace Captura.Audio\n{\n    class NAudioNotificationClient : IMMNotificationClient\n    {\n        void InvokeDevicesUpdated() => DevicesUpdated?.Invoke();\n\n        public void OnDeviceStateChanged(string DeviceId, DeviceState NewState)\n        {\n            InvokeDevicesUpdated();\n        }\n\n        public void OnDeviceAdded(string DeviceId)\n        {\n            InvokeDevicesUpdated();\n        }\n\n        public void OnDeviceRemoved(string DeviceId)\n        {\n            InvokeDevicesUpdated();\n        }\n\n        public void OnDefaultDeviceChanged(DataFlow Flow, Role Role, string DefaultDeviceId)\n        {\n            InvokeDevicesUpdated();\n        }\n\n        public void OnPropertyValueChanged(string DeviceId, PropertyKey Key)\n        {\n        }\n\n        public event Action DevicesUpdated;\n    }\n}"
  },
  {
    "path": "src/Captura.NAudio/NAudioProvider.cs",
    "content": "﻿using NAudio.Wave;\nusing Wf = NAudio.Wave.WaveFormat;\n\nnamespace Captura.Audio\n{\n    abstract class NAudioProvider\n    {\n        public IWaveIn WaveIn { get; }\n\n        protected NAudioProvider(IWaveIn WaveIn)\n        {\n            this.WaveIn = WaveIn;\n\n            NAudioWaveFormat = WaveIn.WaveFormat;\n            WaveFormat = WaveIn.WaveFormat.ToCaptura();\n        }\n\n        public virtual void Dispose()\n        {\n            WaveIn.Dispose();\n        }\n\n        public WaveFormat WaveFormat { get; }\n\n        public Wf NAudioWaveFormat { get; }\n\n        public virtual void Start()\n        {\n            WaveIn.StartRecording();\n        }\n\n        public virtual void Stop()\n        {\n            WaveIn.StopRecording();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.NAudio/NAudioSource.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\nusing NAudio.CoreAudioApi;\n\nnamespace Captura.Audio\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class NAudioSource : IAudioSource\n    {\n        MMDeviceEnumerator _deviceEnumerator = new MMDeviceEnumerator();\n        NAudioNotificationClient _notificationClient = new NAudioNotificationClient();\n\n        public event Action DevicesUpdated;\n\n        public NAudioSource()\n        {\n            _notificationClient.DevicesUpdated += () => DevicesUpdated?.Invoke();\n\n            _deviceEnumerator.RegisterEndpointNotificationCallback(_notificationClient);\n        }\n\n        public string Name { get; } = \"NAudio\";\n\n        public IEnumerable<IAudioItem> Microphones\n        {\n            get\n            {\n                var devices = _deviceEnumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active);\n\n                foreach (var device in devices)\n                {\n                    yield return new NAudioItem(device, false);\n                }\n            }\n        }\n\n        const int DeviceNotFound = unchecked((int)0x80070490);\n\n        public IAudioItem DefaultMicrophone\n        {\n            get\n            {\n                try\n                {\n                    return NAudioItem.DefaultMicrophone;\n                }\n                // Default mic does not exist\n                catch (COMException e) when (e.HResult == DeviceNotFound)\n                {\n                    return null;\n                }\n            }\n        }\n\n        public IEnumerable<IAudioItem> Speakers\n        {\n            get\n            {\n                var devices = _deviceEnumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active);\n\n                foreach (var device in devices)\n                {\n                    yield return new NAudioItem(device, true);\n                }\n            }\n        }\n\n        public IAudioItem DefaultSpeaker\n        {\n            get\n            {\n                try\n                {\n                    return NAudioItem.DefaultSpeaker;\n                }\n                // Default speaker does not exist\n                catch (COMException e) when (e.HResult == DeviceNotFound)\n                {\n                    return null;\n                }\n            }\n        }\n\n        public void Dispose()\n        {\n            _deviceEnumerator.UnregisterEndpointNotificationCallback(_notificationClient);\n            _notificationClient = null;\n\n            _deviceEnumerator.Dispose();\n            _deviceEnumerator = null;\n        }\n\n        public IAudioProvider GetAudioProvider(IAudioItem Microphone, IAudioItem Speaker)\n        {\n            switch ((Microphone, Speaker))\n            {\n                case (null, NAudioItem speaker):\n                    return new MixedAudioProvider(new WasapiLoopbackCaptureProvider(speaker.Device));\n\n                case (NAudioItem mic, null):\n                    return new MixedAudioProvider(new WasapiCaptureProvider(mic.Device));\n\n                case (NAudioItem mic, NAudioItem speaker):\n                    return new MixedAudioProvider(\n                        new WasapiCaptureProvider(mic.Device),\n                        new WasapiLoopbackCaptureProvider(speaker.Device));\n\n                default:\n                    return null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.NAudio/WasapiCaptureProvider.cs",
    "content": "﻿using NAudio.CoreAudioApi;\n\nnamespace Captura.Audio\n{\n    class WasapiCaptureProvider : NAudioProvider\n    {\n        public WasapiCaptureProvider(MMDevice Device)\n            : base(new WasapiCapture(Device)) { }\n    }\n}"
  },
  {
    "path": "src/Captura.NAudio/WasapiLoopbackCaptureProvider.cs",
    "content": "﻿using NAudio.CoreAudioApi;\nusing NAudio.Wave;\n\nnamespace Captura.Audio\n{\n    class WasapiLoopbackCaptureProvider : NAudioProvider\n    {\n        readonly IWavePlayer _wasapiOut;\n\n        public WasapiLoopbackCaptureProvider(MMDevice Device)\n            : base(new WasapiLoopbackCapture(Device))\n        {\n            _wasapiOut = new WasapiOut(Device, AudioClientShareMode.Shared, true, 50);\n            \n            // Mix Format should be used in Shared mode\n            using var audioClient = Device.AudioClient;\n            _wasapiOut.Init(new SilenceProvider(audioClient.MixFormat));\n        }\n\n        public override void Start()\n        {\n            _wasapiOut.Play();\n\n            base.Start();\n        }\n\n        public override void Stop()\n        {\n            base.Stop();\n\n            _wasapiOut.Pause();\n        }\n\n        public override void Dispose()\n        {\n            base.Dispose();\n\n            _wasapiOut.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.NAudio/WaveFormatExtensions.cs",
    "content": "﻿using Wf = NAudio.Wave.WaveFormat;\nusing WfEnc = NAudio.Wave.WaveFormatEncoding;\n\nnamespace Captura.Audio\n{\n    static class WaveFormatExtensions\n    {\n        public static WaveFormat ToCaptura(this Wf Wf)\n        {\n            return Wf.Encoding == WfEnc.IeeeFloat\n                ? WaveFormat.CreateIeeeFloatWaveFormat(Wf.SampleRate, Wf.Channels)\n                : new WaveFormat(Wf.SampleRate, Wf.BitsPerSample, Wf.Channels);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.SharpAvi/AviCodec.cs",
    "content": "﻿using SharpAvi;\n\nnamespace Captura.SharpAvi\n{\n    /// <summary>\n    /// Represents an Avi Codec.\n    /// </summary>\n    class AviCodec\n    {\n        // ReSharper disable once InconsistentNaming\n        internal FourCC FourCC { get; }\n\n        /// <summary>\n        /// Name of the Codec\n        /// </summary>\n        public string Name { get; }\n\n        // ReSharper disable once InconsistentNaming\n        internal AviCodec(FourCC FourCC, string Name)\n        {\n            this.FourCC = FourCC;\n            this.Name = Name;\n        }\n        \n        /// <summary>\n        /// Quality of the encoded Video... 0 to 100 (default is 70) (Not supported by all Codecs). \n        /// </summary>\n        public int Quality { get; set; } = 70;\n\n        /// <summary>Identifier used for non-compressed data.</summary>\n        public static AviCodec Uncompressed { get; } = new AviCodec(new FourCC(0), \"Uncompressed\");\n\n        /// <summary>Motion JPEG.</summary>\n        public static AviCodec MotionJpeg { get; } = new AviCodec(new FourCC(\"MJPG\"), \"Motion Jpeg\");\n\n        public static AviCodec Lagarith { get; } = new AviCodec(new FourCC(\"LAGS\"), \"Lagarith (Install Manually)\");\n    }\n}\n"
  },
  {
    "path": "src/Captura.SharpAvi/AviWriter.cs",
    "content": "﻿using System;\nusing Captura.Audio;\nusing Captura.Video;\nusing SharpAvi.Codecs;\nusing SharpAvi.Output;\nusing AviInternalWriter = SharpAvi.Output.AviWriter;\n\nnamespace Captura.SharpAvi\n{\n    /// <summary>\n    /// Writes an AVI file.\n    /// </summary>\n    class AviWriter : IVideoFileWriter\n    {\n        #region Fields\n        AviInternalWriter _writer;\n        IAviVideoStream _videoStream;\n        IAviAudioStream _audioStream;\n        byte[] _videoBuffer;\n        readonly AviCodec _codec;\n        readonly object _syncLock = new object();\n        \n        /// <summary>\n        /// Gets whether Audio is recorded.\n        /// </summary>\n        public bool SupportsAudio => _audioStream != null;\n        #endregion\n\n        /// <summary>\n        /// Creates a new instance of <see cref=\"AviWriter\"/>.\n        /// </summary>\n        /// <param name=\"FileName\">Output file path.</param>\n        /// <param name=\"Codec\">The Avi Codec.</param>\n        /// <param name=\"ImageProvider\">The image source.</param>\n        /// <param name=\"FrameRate\">Video Frame Rate.</param>\n        /// <param name=\"AudioProvider\">The audio source. null = no audio.</param>\n        public AviWriter(string FileName, AviCodec Codec, IImageProvider ImageProvider, int FrameRate, IAudioProvider AudioProvider = null)\n        {\n            _codec = Codec;\n\n            _videoBuffer = new byte[ImageProvider.Width * ImageProvider.Height * 4];\n\n            _writer = new AviInternalWriter(FileName)\n            {\n                FramesPerSecond = FrameRate,\n                EmitIndex1 = true\n            };\n\n            CreateVideoStream(ImageProvider.Width, ImageProvider.Height);\n\n            if (AudioProvider != null)\n                CreateAudioStream(AudioProvider);\n        }\n        \n        /// <summary>\n        /// Writes an Image frame.\n        /// </summary>\n        public void WriteFrame(IBitmapFrame Frame)\n        {\n            if (!(Frame is RepeatFrame))\n            {\n                using (Frame)\n                {\n                    Frame.CopyTo(_videoBuffer);\n                }\n            }\n\n            lock (_syncLock)\n                _videoStream.WriteFrame(true, _videoBuffer, 0, _videoBuffer.Length);\n        }\n\n        void CreateVideoStream(int Width, int Height)\n        {\n            // Select encoder type based on FOURCC of codec\n            if (_codec == AviCodec.Uncompressed)\n                _videoStream = _writer.AddUncompressedVideoStream(Width, Height);\n            else if (_codec == AviCodec.MotionJpeg)\n            {\n                // MotionJpegVideoStream implementation allocates multiple WriteableBitmap for every thread\n                // Use SingleThreadWrapper to reduce allocation\n                var encoderFactory = new Func<IVideoEncoder>(() => new MotionJpegVideoEncoderWpf(Width, Height, _codec.Quality));\n                var encoder = new SingleThreadedVideoEncoderWrapper(encoderFactory);\n\n                _videoStream = _writer.AddEncodingVideoStream(encoder, true, Width, Height);\n            }\n            else\n            {\n                _videoStream = _writer.AddMpeg4VideoStream(Width, Height,\n                    (double)_writer.FramesPerSecond,\n                    // It seems that all tested MPEG-4 VfW codecs ignore the quality affecting parameters passed through VfW API\n                    // They only respect the settings from their own configuration dialogs, and Mpeg4VideoEncoder currently has no support for this\n                    0,\n                    _codec.Quality,\n                    // Most of VfW codecs expect single-threaded use, so we wrap this encoder to special wrapper\n                    // Thus all calls to the encoder (including its instantiation) will be invoked on a single thread although encoding (and writing) is performed asynchronously\n                    _codec.FourCC,\n                    true);\n            }\n\n            _videoStream.Name = \"Video\";\n        }\n\n        void CreateAudioStream(IAudioProvider AudioProvider)\n        {\n            _audioStream = _writer.AddEncodingAudioStream(new IAudioProviderAdapter(AudioProvider));\n\n            _audioStream.Name = \"Audio\";\n        }\n\n        /// <summary>\n        /// Write audio block to Audio Stream.\n        /// </summary>\n        /// <param name=\"Buffer\">Buffer containing audio data.</param>\n        /// <param name=\"Length\">Length of audio data in bytes.</param>\n        public void WriteAudio(byte[] Buffer, int Offset, int Length)\n        {\n            lock (_syncLock)\n                _audioStream?.WriteBlock(Buffer, Offset, Length);\n        }\n\n        /// <summary>\n        /// Frees all resources used by this object.\n        /// </summary>\n        public void Dispose()\n        {\n            lock (_syncLock)\n            {\n                _writer.Close();\n                _writer = null;\n\n                _videoStream = null;\n                _audioStream = null;\n            }\n\n            _videoBuffer = null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.SharpAvi/Captura.SharpAvi.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net472</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"SharpAvi\" Version=\"2.1.2\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Captura.SharpAvi/IAudioProviderAdapter.cs",
    "content": "﻿using System;\nusing System.IO;\nusing Captura.Audio;\nusing IAudioEncoder = SharpAvi.Codecs.IAudioEncoder;\n\nnamespace Captura.SharpAvi\n{\n    /// <summary>\n    /// Enables a Screna based Audio Provider to be used with SharpAvi.\n    /// </summary>\n    class IAudioProviderAdapter : IAudioEncoder\n    {\n        readonly IAudioProvider _provider;\n\n        public IAudioProviderAdapter(IAudioProvider Provider)\n        {\n            _provider = Provider;\n        }\n\n        public int BitsPerSample => _provider.WaveFormat.BitsPerSample;\n\n        public int BytesPerSecond => _provider.WaveFormat.AverageBytesPerSecond;\n\n        public int ChannelCount => _provider.WaveFormat.Channels;\n\n        public short Format => (short)_provider.WaveFormat.Encoding;\n\n        public byte[] FormatSpecificData\n        {\n            get\n            {\n                var extraSize = _provider.WaveFormat.ExtraSize;\n\n                if (extraSize <= 0)\n                    return null;\n\n                using var ms = new MemoryStream();\n                using var writer = new BinaryWriter(ms);\n                _provider.WaveFormat.Serialize(writer);\n\n                var formatData = new byte[extraSize];\n\n                ms.Seek(18, SeekOrigin.Begin);\n\n                ms.Read(formatData, 0, extraSize);\n\n                return formatData;\n            }\n        }\n\n        public int Granularity => _provider.WaveFormat.BlockAlign;\n\n        public int SamplesPerSecond => _provider.WaveFormat.SampleRate;\n\n        public int EncodeBlock(byte[] Source, int SourceOffset, int SourceCount, byte[] Destination, int DestinationOffset)\n        {\n            Array.Copy(Source, SourceOffset, Destination, DestinationOffset, SourceCount);\n\n            return SourceCount;\n        }\n\n        public int Flush(byte[] Destination, int DestinationOffset) => 0;\n\n        public int GetMaxEncodedLength(int SourceCount) => SourceCount;\n    }\n}"
  },
  {
    "path": "src/Captura.SharpAvi/SharpAviItem.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.SharpAvi\n{\n    class SharpAviItem : IVideoWriterItem\n    {\n        readonly AviCodec _codec;\n\n        public SharpAviItem(AviCodec Codec, string Description)\n        {\n            _codec = Codec;\n            this.Description = Description;\n        }\n\n        public string Extension { get; } = \".avi\";\n\n        public string Description { get; }\n\n        public IVideoFileWriter GetVideoFileWriter(VideoWriterArgs Args)\n        {\n            _codec.Quality = Args.VideoQuality;\n\n            return new AviWriter(Args.FileName, _codec, Args.ImageProvider, Args.FrameRate, Args.AudioProvider);\n        }\n        \n        public override string ToString() => _codec.Name;\n    }\n}\n"
  },
  {
    "path": "src/Captura.SharpAvi/SharpAviWriterProvider.cs",
    "content": "﻿using SharpAvi.Codecs;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing Captura.Video;\n\nnamespace Captura.SharpAvi\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class SharpAviWriterProvider : IVideoWriterProvider\n    {\n        public string Name => \"SharpAvi\";\n\n        public IEnumerator<IVideoWriterItem> GetEnumerator()\n        {\n            yield return new SharpAviItem(AviCodec.MotionJpeg, \"Motion JPEG encoder using WPF's JPG encoder\");\n            yield return new SharpAviItem(AviCodec.Uncompressed, \"Uncompressed Avi\");\n            yield return new SharpAviItem(AviCodec.Lagarith, \"Lagarith codec needs to be installed manually and configured to use RGB mode with Null Frames disabled.\");\n\n            foreach (var codec in Mpeg4VideoEncoderVcm.GetAvailableCodecs())\n                yield return new SharpAviItem(new AviCodec(codec.Codec, codec.Name), \"\");\n        }\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        public override string ToString() => Name;\n\n        public IVideoWriterItem ParseCli(string Cli)\n        {\n            if (ServiceProvider.FileExists(\"SharpAvi.dll\") && Regex.IsMatch(Cli, @\"^sharpavi:\\d+$\"))\n            {\n                var index = int.Parse(Cli.Substring(9));\n\n                var writers = this.ToArray();\n\n                if (index < writers.Length)\n                {\n                    return writers[index];\n                }\n            }\n\n            return null;\n        }\n\n        public string Description => \"Encode Avi videos using SharpAvi.\";\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/Captura.ViewCore.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net472</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Core\\Captura.Core.csproj\" />\n    <ProjectReference Include=\"..\\Screna\\Screna.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"ReactiveProperty\" Version=\"6.1.3\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Captura.ViewCore/FFmpegLog.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\n\nnamespace Captura.FFmpeg\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FFmpegLog : NotifyPropertyChanged, IFFmpegLogRepository\n    {\n        public FFmpegLog()\n        {\n            LogItems = new ReadOnlyObservableCollection<FFmpegLogItem>(_logItems);\n        }\n\n        readonly ObservableCollection<FFmpegLogItem> _logItems = new ObservableCollection<FFmpegLogItem>();\n\n        public ReadOnlyObservableCollection<FFmpegLogItem> LogItems { get; }\n\n        public FFmpegLogItem CreateNew(string Name, string Args)\n        {\n            var item = new FFmpegLogItem(Name, Args);\n\n            _logItems.Insert(0, item);\n\n            return item;\n        }\n\n        public void Remove(FFmpegLogItem Item)\n        {\n            _logItems.Remove(Item);\n        }\n\n        public IEnumerator<IFFmpegLogEntry> GetEnumerator() => _logItems.GetEnumerator();\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        IFFmpegLogEntry IFFmpegLogRepository.CreateNew(string Name, string Args) => CreateNew(Name, Args);\n\n        void IFFmpegLogRepository.Remove(IFFmpegLogEntry Entry)\n        {\n            if (Entry is FFmpegLogItem logItem)\n            {\n                Remove(logItem);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.ViewCore/FileContentItem.cs",
    "content": "﻿using System.IO;\n\nnamespace Captura.Models\n{\n    public class FileContentItem\n    {\n        public string FileName { get; }\n\n        public FileContentItem(string FileName)\n        {\n            this.FileName = FileName;\n\n            Name = Path.GetFileNameWithoutExtension(FileName);\n        }\n\n        public string Name { get; }\n\n        public string Content => File.Exists(FileName) ? File.ReadAllText(FileName) : null;\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/FileNameFormatGroup.cs",
    "content": "﻿namespace Captura.Models\n{\n    public class FileNameFormatGroup\n    {\n        public FileNameFormatGroup(string Name, FileNameFormatItem[] Formats)\n        {\n            this.Name = Name;\n            this.Formats = Formats;\n        }\n\n        public string Name { get; }\n\n        public FileNameFormatItem[] Formats { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/FileNameFormatItem.cs",
    "content": "﻿namespace Captura.Models\n{\n    public class FileNameFormatItem\n    {\n        public FileNameFormatItem(string Format, string Description)\n        {\n            this.Format = Format;\n            this.Description = Description;\n        }\n\n        public string Format { get; }\n\n        public string Description { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/HotkeyActor.cs",
    "content": "﻿using Captura.Hotkeys;\nusing Captura.Models;\nusing Captura.Video;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class HotkeyActor : IHotkeyActor\n    {\n        readonly ScreenShotViewModel _screenShotViewModel;\n        readonly RecordingViewModel _recordingViewModel;\n        readonly Settings _settings;\n        readonly VideoSourcesViewModel _videoSourcesViewModel;\n        readonly RegionSourceProvider _regionSourceProvider;\n\n        public HotkeyActor(ScreenShotViewModel ScreenShotViewModel,\n            RecordingViewModel RecordingViewModel,\n            Settings Settings,\n            VideoSourcesViewModel VideoSourcesViewModel,\n            RegionSourceProvider RegionSourceProvider)\n        {\n            _screenShotViewModel = ScreenShotViewModel;\n            _recordingViewModel = RecordingViewModel;\n            _settings = Settings;\n            _videoSourcesViewModel = VideoSourcesViewModel;\n            _regionSourceProvider = RegionSourceProvider;\n        }\n\n        public void Act(ServiceName Service)\n        {\n            switch (Service)\n            {\n                case ServiceName.Recording:\n                    _recordingViewModel.RecordCommand.ExecuteIfCan();\n                    break;\n\n                case ServiceName.Pause:\n                    _recordingViewModel.PauseCommand.ExecuteIfCan();\n                    break;\n\n                case ServiceName.ScreenShot:\n                    _screenShotViewModel.ScreenShotCommand.ExecuteIfCan();\n                    break;\n\n                case ServiceName.ActiveScreenShot:\n                    _screenShotViewModel.ScreenShotActiveCommand.ExecuteIfCan();\n                    break;\n\n                case ServiceName.DesktopScreenShot:\n                    _screenShotViewModel.ScreenShotDesktopCommand.ExecuteIfCan();\n                    break;\n\n                case ServiceName.ToggleMouseClicks:\n                    _settings.Clicks.Display = !_settings.Clicks.Display;\n                    break;\n\n                case ServiceName.ToggleKeystrokes:\n                    _settings.Keystrokes.Display = !_settings.Keystrokes.Display;\n                    break;\n\n                case ServiceName.ScreenShotRegion:\n                    _screenShotViewModel.ScreenshotRegionCommand.ExecuteIfCan();\n                    break;\n\n                case ServiceName.ScreenShotScreen:\n                    _screenShotViewModel.ScreenshotScreenCommand.ExecuteIfCan();\n                    break;\n\n                case ServiceName.ScreenShotWindow:\n                    _screenShotViewModel.ScreenshotWindowCommand.ExecuteIfCan();\n                    break;\n\n                case ServiceName.ToggleRegionPicker:\n                    // Stop any recording in progress\n                    if (_recordingViewModel.RecorderState.Value != RecorderState.NotRecording)\n                    {\n                        _recordingViewModel.RecordCommand.Execute(null);\n                    }\n\n                    if (_videoSourcesViewModel.SelectedVideoSourceKind != _regionSourceProvider)\n                    {\n                        _videoSourcesViewModel.SelectedVideoSourceKind = _regionSourceProvider;\n\n                        if (_settings.RegionPickerHotkeyAutoStartRecording)\n                        {\n                            _recordingViewModel.RecordCommand.Execute(null);\n                        }\n                    }\n                    else _videoSourcesViewModel.SetDefaultSource();\n                    break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/RememberByName.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing Captura.Video;\nusing Captura.ViewModels;\nusing Captura.Webcam;\n\nnamespace Captura.Models\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class RememberByName\n    {\n        readonly Settings _settings;\n        readonly VideoSourcesViewModel _videoSourcesViewModel;\n        readonly VideoWritersViewModel _videoWritersViewModel;\n        readonly AudioSourceViewModel _audioSourceViewModel;\n        readonly WebcamModel _webcamModel;\n        readonly ScreenShotModel _screenShotModel;\n        readonly IEnumerable<IVideoSourceProvider> _videoSourceProviders;\n\n        public RememberByName(Settings Settings,\n            VideoSourcesViewModel VideoSourcesViewModel,\n            VideoWritersViewModel VideoWritersViewModel,\n            AudioSourceViewModel AudioSourceViewModel,\n            ScreenShotModel ScreenShotModel,\n            IEnumerable<IVideoSourceProvider> VideoSourceProviders,\n            WebcamModel WebcamModel)\n        {\n            _settings = Settings;\n            _videoSourcesViewModel = VideoSourcesViewModel;\n            _videoWritersViewModel = VideoWritersViewModel;\n            _audioSourceViewModel = AudioSourceViewModel;\n            _screenShotModel = ScreenShotModel;\n            _videoSourceProviders = VideoSourceProviders;\n            _webcamModel = WebcamModel;\n        }\n\n        public void Remember()\n        {\n            // Remember Video Source\n            _settings.Video.SourceKind = _videoSourcesViewModel\n                .SelectedVideoSourceKind\n                .Name;\n\n            _settings.Video.Source = _videoSourcesViewModel\n                .SelectedVideoSourceKind\n                .Serialize();\n\n            // Remember Video Codec\n            _settings.Video.WriterKind = _videoWritersViewModel\n                .SelectedVideoWriterKind\n                .Name;\n\n            _settings.Video.Writer = _videoWritersViewModel\n                .SelectedVideoWriter\n                .ToString();\n\n            // Remember Post Writer\n            _settings.Video.PostWriter = _videoWritersViewModel.SelectedPostWriter.ToString();\n\n            // Remember Audio Sources\n            _settings.Audio.Microphone = _audioSourceViewModel.SelectedMicrophone?.Name;\n\n            _settings.Audio.Speaker = _audioSourceViewModel.SelectedSpeaker?.Name;\n\n            // Remember ScreenShot Target\n            _settings.ScreenShots.SaveTargets = _screenShotModel\n                .AvailableImageWriters\n                .Where(M => M.Active)\n                .Select(M => M.Display)\n                .ToArray();\n\n            // Remember Webcam\n            _settings.Video.Webcam = _webcamModel\n                .SelectedCam\n                .Name;\n\n            // Remember Steps writer\n            _settings.Steps.Writer = _videoWritersViewModel\n                .SelectedStepsWriter\n                ?.ToString();\n        }\n\n        void RestoreVideoSource()\n        {\n            if (string.IsNullOrEmpty(_settings.Video.SourceKind))\n                return;\n\n            var provider = _videoSourceProviders\n                .FirstOrDefault(M => M.Name == _settings.Video.SourceKind);\n\n            if (provider == null)\n                return;\n\n            if (provider.Deserialize(_settings.Video.Source))\n            {\n                _videoSourcesViewModel.RestoreSourceKind(provider);\n            }\n        }\n\n        void RestoreVideoCodec()\n        {\n            if (string.IsNullOrEmpty(_settings.Video.WriterKind))\n                return;\n\n            var kind = _videoWritersViewModel\n                .VideoWriterProviders\n                .FirstOrDefault(W => W.Name == _settings.Video.WriterKind);\n\n            if (kind == null)\n                return;\n\n            _videoWritersViewModel.SelectedVideoWriterKind = kind;\n\n            var codec = _videoWritersViewModel\n                .AvailableVideoWriters\n                .FirstOrDefault(C => C.ToString() == _settings.Video.Writer);\n\n            if (codec != null)\n                _videoWritersViewModel.SelectedVideoWriter = codec;\n        }\n\n        public void RestoreRemembered()\n        {\n            RestoreVideoSource();\n\n            RestoreVideoCodec();\n\n            // Restore Post Writer\n            var codec = _videoWritersViewModel.AvailablePostWriters.FirstOrDefault(C => C.ToString() == _settings.Video.PostWriter);\n\n            if (codec != null)\n                _videoWritersViewModel.SelectedPostWriter = codec;\n\n            // Restore Microphone\n            var mic = _audioSourceViewModel.AvailableMicrophones.FirstOrDefault(M => M.Name == _settings.Audio.Microphone);\n\n            if (mic != null)\n                _audioSourceViewModel.SelectedMicrophone = mic;\n\n            // Restore Loopback Speaker\n            var speaker = _audioSourceViewModel.AvailableSpeakers.FirstOrDefault(M => M.Name == _settings.Audio.Speaker);\n\n            if (speaker != null)\n                _audioSourceViewModel.SelectedSpeaker = speaker;\n\n            // Restore ScreenShot Target\n            if (_settings.ScreenShots.SaveTargets != null)\n            {\n                foreach (var imageWriter in _screenShotModel.AvailableImageWriters)\n                {\n                    imageWriter.Active = _settings\n                        .ScreenShots\n                        .SaveTargets\n                        .Contains(imageWriter.Display);\n                }\n\n                // Activate First if none\n                if (!_screenShotModel.AvailableImageWriters.Any(M => M.Active))\n                {\n                    _screenShotModel.AvailableImageWriters[0].Active = true;\n                }\n            }\n\n            // Restore Webcam\n            if (!string.IsNullOrEmpty(_settings.Video.Webcam))\n            {\n                var webcam = _webcamModel\n                    .AvailableCams\n                    .FirstOrDefault(C => C.Name == _settings.Video.Webcam);\n\n                if (webcam != null)\n                {\n                    _webcamModel.SelectedCam = webcam;\n                }\n            }\n\n            // Restore Steps writer\n            if (!string.IsNullOrEmpty(_settings.Steps.Writer))\n            {\n                var stepsWriter = _videoWritersViewModel\n                    .AvailableStepWriters\n                    .FirstOrDefault(M => M.ToString() == _settings.Steps.Writer);\n\n                if (stepsWriter != null)\n                {\n                    _videoWritersViewModel.SelectedStepsWriter = stepsWriter;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/SoundsViewModelItem.cs",
    "content": "﻿using System.IO;\nusing System.Windows.Input;\nusing Captura.Audio;\nusing Captura.Models;\nusing Reactive.Bindings;\n\nnamespace Captura.ViewModels\n{\n    public class SoundsViewModelItem : NotifyPropertyChanged\n    {\n        readonly SoundSettings _settings;\n\n        public SoundsViewModelItem(SoundKind SoundKind, IDialogService DialogService, SoundSettings Settings)\n        {\n            this.SoundKind = SoundKind;\n            _settings = Settings;\n\n            ResetCommand = new ReactiveCommand()\n                .WithSubscribe(() => FileName = null);\n\n            SetCommand = new ReactiveCommand()\n                .WithSubscribe(() =>\n                {\n                    var folder = DialogService.PickFile(Path.GetDirectoryName(FileName), \"\");\n\n                    if (folder != null)\n                        FileName = folder;\n                });\n        }\n\n        public string FileName\n        {\n            get => _settings.Items.TryGetValue(SoundKind, out var value) ? value : null;\n            set\n            {\n                if (_settings.Items.ContainsKey(SoundKind))\n                {\n                    _settings.Items[SoundKind] = value;\n                }\n                else _settings.Items.Add(SoundKind, value);\n\n                OnPropertyChanged();\n            }\n        }\n\n        public SoundKind SoundKind { get; }\n\n        public ICommand ResetCommand { get; }\n\n        public ICommand SetCommand { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewCoreModule.cs",
    "content": "﻿using Captura.FFmpeg;\nusing Captura.Hotkeys;\nusing Captura.Models;\n\nnamespace Captura.ViewModels\n{\n    public class ViewCoreModule : IModule\n    {\n        public void OnLoad(IBinder Binder)\n        {\n            Binder.BindSingleton<CrashLogsViewModel>();\n            Binder.BindSingleton<FileNameFormatViewModel>();\n            Binder.BindSingleton<LicensesViewModel>();\n            Binder.BindSingleton<ProxySettingsViewModel>();\n            Binder.BindSingleton<SoundsViewModel>();\n            Binder.BindSingleton<RecentViewModel>();\n            Binder.BindSingleton<UpdateCheckerViewModel>();\n            Binder.BindSingleton<ScreenShotViewModel>();\n            Binder.BindSingleton<RecordingViewModel>();\n            Binder.BindSingleton<MainViewModel>();\n            Binder.BindSingleton<HotkeysViewModel>();\n            Binder.BindSingleton<FFmpegLogViewModel>();\n            Binder.BindSingleton<FFmpegCodecsViewModel>();\n            Binder.BindSingleton<ViewConditionsModel>();\n\n            Binder.BindSingleton<VideoSourcesViewModel>();\n            Binder.BindSingleton<VideoWritersViewModel>();\n\n            Binder.BindSingleton<AudioSourceViewModel>();\n\n            Binder.BindSingleton<CustomOverlaysViewModel>();\n            Binder.BindSingleton<CustomImageOverlaysViewModel>();\n            Binder.BindSingleton<CensorOverlaysViewModel>();\n\n            Binder.BindSingleton<FFmpegLog>();\n            Binder.Bind<IFFmpegLogRepository>(ServiceProvider.Get<FFmpegLog>);\n\n            Binder.Bind<IHotkeyActor, HotkeyActor>();\n        }\n\n        public void Dispose() { }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/AudioSourceViewModel.cs",
    "content": "﻿using System;\nusing Captura.Audio;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing System.Reactive;\nusing System.Reactive.Linq;\nusing System.Windows.Input;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.Models\n{\n    public class AudioSourceViewModel : NotifyPropertyChanged\n    {\n        readonly IAudioSource _audioSource;\n\n        readonly ObservableCollection<IAudioItem> _microphones = new ObservableCollection<IAudioItem>(),\n            _speakers = new ObservableCollection<IAudioItem>();\n\n        public ReadOnlyObservableCollection<IAudioItem> AvailableMicrophones { get; }\n\n        public ReadOnlyObservableCollection<IAudioItem> AvailableSpeakers { get; }\n\n        // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable\n        readonly IObservable<Unit> _refreshObservable;\n\n        public AudioSourceViewModel(IAudioSource AudioSource)\n        {\n            _audioSource = AudioSource;\n\n            AvailableMicrophones = new ReadOnlyObservableCollection<IAudioItem>(_microphones);\n            AvailableSpeakers = new ReadOnlyObservableCollection<IAudioItem>(_speakers);\n\n            Refresh();\n\n            RefreshCommand = new DelegateCommand(Refresh);\n\n            SelectedMicPeakLevel = Observable.Interval(TimeSpan.FromMilliseconds(50))\n                .Where(M => ListeningPeakLevel)\n                .ObserveOnUIDispatcher()\n                .Select(M => SelectedMicrophone?.PeakLevel ?? 0)\n                .ToReadOnlyReactivePropertySlim();\n\n            SelectedSpeakerPeakLevel = Observable.Interval(TimeSpan.FromMilliseconds(50))\n                .Where(M => ListeningPeakLevel)\n                .ObserveOnUIDispatcher()\n                .Select(M => SelectedSpeaker?.PeakLevel ?? 0)\n                .ToReadOnlyReactivePropertySlim();\n\n            _refreshObservable = Observable.FromEvent(M => AudioSource.DevicesUpdated += M,\n                M => AudioSource.DevicesUpdated -= M)\n                .Throttle(TimeSpan.FromSeconds(0.5));\n\n            _refreshObservable\n                .ObserveOnUIDispatcher()\n                .Subscribe(M => Refresh());\n        }\n\n        void RefreshMics()\n        {\n            var lastMicName = SelectedMicrophone?.Name;\n\n            foreach (var microphone in _microphones)\n            {\n                microphone.Dispose();\n            }\n\n            _microphones.Clear();\n\n            if (_audioSource.DefaultMicrophone is { } defaultMicrophone)\n            {\n                _microphones.Add(defaultMicrophone);\n            }\n\n            foreach (var mic in _audioSource.Microphones)\n            {\n                _microphones.Add(mic);\n            }\n\n            var matchMic = _microphones.FirstOrDefault(M => M.Name == lastMicName);\n\n            SelectedMicrophone = matchMic;\n        }\n\n        void RefreshSpeakers()\n        {\n            var lastSpeakerName = SelectedSpeaker?.Name;\n\n            foreach (var speaker in _speakers)\n            {\n                speaker.Dispose();\n            }\n\n            _speakers.Clear();\n            \n            if (_audioSource.DefaultSpeaker is { } defaultSpeaker)\n            {\n                _speakers.Add(defaultSpeaker);\n            }\n\n            foreach (var speaker in _audioSource.Speakers)\n            {\n                _speakers.Add(speaker);\n            }\n\n            var matchSpeaker = _speakers.FirstOrDefault(M => M.Name == lastSpeakerName);\n\n            SelectedSpeaker = matchSpeaker;\n        }\n\n        void Refresh()\n        {\n            RefreshMics();\n\n            RefreshSpeakers();\n        }\n\n        public ICommand RefreshCommand { get; }\n\n        bool _listenPeakLvl;\n\n        public bool ListeningPeakLevel\n        {\n            get => _listenPeakLvl;\n            set\n            {\n                if (_listenPeakLvl && !value)\n                {\n                    _listenPeakLvl = false;\n\n                    SelectedMicrophone?.StopListeningForPeakLevel();\n                    SelectedSpeaker?.StopListeningForPeakLevel();\n                }\n                else if (!_listenPeakLvl && value)\n                {\n                    _listenPeakLvl = true;\n\n                    SelectedMicrophone?.StartListeningForPeakLevel();\n                    SelectedSpeaker?.StartListeningForPeakLevel();\n                }\n            }\n        }\n\n        public string Name => _audioSource.Name;\n\n        IAudioItem _selectedMicrophone, _selectedSpeaker;\n\n        public IAudioItem SelectedMicrophone\n        {\n            get => _selectedMicrophone;\n            set\n            {\n                var old = SelectedMicrophone;\n\n                if (Set(ref _selectedMicrophone, value ?? AvailableMicrophones.FirstOrDefault()))\n                {\n                    old?.StopListeningForPeakLevel();\n\n                    if (ListeningPeakLevel)\n                    {\n                        _selectedMicrophone?.StartListeningForPeakLevel();\n                    }\n                }\n            }\n        }\n\n        public IAudioItem SelectedSpeaker\n        {\n            get => _selectedSpeaker;\n            set\n            {\n                var old = SelectedSpeaker;\n\n                if (Set(ref _selectedSpeaker, value ?? AvailableSpeakers.FirstOrDefault()))\n                {\n                    old?.StopListeningForPeakLevel();\n\n                    if (ListeningPeakLevel)\n                    {\n                        _selectedSpeaker?.StartListeningForPeakLevel();\n                    }\n                }\n            }\n        }\n\n        public IReadOnlyReactiveProperty<double> SelectedMicPeakLevel { get; }\n\n        public IReadOnlyReactiveProperty<double> SelectedSpeakerPeakLevel { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/CensorOverlaysViewModel.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class CensorOverlaysViewModel : OverlayListViewModel<CensorOverlaySettings>\n    {\n        public CensorOverlaysViewModel(Settings Settings) : base(Settings.Censored)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/CrashLogsViewModel.cs",
    "content": "﻿using System.Collections.ObjectModel;\nusing System.IO;\nusing System.Linq;\nusing System.Reactive.Linq;\nusing System.Windows.Input;\nusing Captura.Models;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class CrashLogsViewModel : NotifyPropertyChanged\n    {\n        public ICommand CopyToClipboardCommand { get; }\n        public ICommand RemoveCommand { get; }\n\n        readonly ObservableCollection<FileContentItem> _crashLogs;\n\n        public ReadOnlyObservableCollection<FileContentItem> CrashLogs { get; }\n\n        public CrashLogsViewModel()\n        {\n            var folder = Path.Combine(ServiceProvider.SettingsDir, \"Crashes\");\n\n            if (Directory.Exists(folder))\n            {\n                _crashLogs = new ObservableCollection<FileContentItem>(Directory\n                    .EnumerateFiles(folder)\n                    .Select(FileName => new FileContentItem(FileName))\n                    .Reverse());\n\n                CrashLogs = new ReadOnlyObservableCollection<FileContentItem>(_crashLogs);\n\n                if (CrashLogs.Count > 0)\n                {\n                    SelectedCrashLog = CrashLogs[0];\n                }\n            }\n\n            CopyToClipboardCommand = this\n                .ObserveProperty(M => M.SelectedCrashLog)\n                .Select(M => M != null)\n                .ToReactiveCommand()\n                .WithSubscribe(() => SelectedCrashLog.Content.WriteToClipboard());\n\n            RemoveCommand = this\n                .ObserveProperty(M => M.SelectedCrashLog)\n                .Select(M => M != null)\n                .ToReactiveCommand()\n                .WithSubscribe(OnRemoveExecute);\n        }\n\n        void OnRemoveExecute()\n        {\n            if (SelectedCrashLog == null)\n                return;\n\n            if (File.Exists(SelectedCrashLog.FileName))\n            {\n                File.Delete(SelectedCrashLog.FileName);\n            }\n\n            _crashLogs.Remove(SelectedCrashLog);\n\n            SelectedCrashLog = CrashLogs.Count > 0 ? CrashLogs[0] : null;\n        }\n\n        FileContentItem _selectedCrashLog;\n\n        public FileContentItem SelectedCrashLog\n        {\n            get => _selectedCrashLog;\n            set => Set(ref _selectedCrashLog, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/CustomImageOverlaysViewModel.cs",
    "content": "﻿using System;\nusing System.Windows.Input;\nusing Captura.Models;\nusing Captura.Video;\nusing Reactive.Bindings;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class CustomImageOverlaysViewModel : OverlayListViewModel<CustomImageOverlaySettings>\n    {\n        readonly IDialogService _dialogService;\n\n        public CustomImageOverlaysViewModel(Settings Settings, IDialogService DialogService) : base(Settings.ImageOverlays)\n        {\n            _dialogService = DialogService;\n\n            ChangeCommand = new ReactiveCommand<CustomImageOverlaySettings>()\n                .WithSubscribe(Change);\n        }\n\n        public ICommand ChangeCommand { get; }\n\n        void Change(CustomImageOverlaySettings M)\n        {\n            var fileName = _dialogService.PickFile(\n                Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),\n                \"Select Image\");\n\n            if (fileName != null)\n            {\n                M.Source = fileName;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/CustomOverlaysViewModel.cs",
    "content": "﻿using Captura.Video;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class CustomOverlaysViewModel : OverlayListViewModel<CustomOverlaySettings>\n    {\n        public CustomOverlaysViewModel(Settings Settings) : base(Settings.TextOverlays)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/FFmpegCodecsViewModel.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing System.Windows.Input;\nusing Captura.FFmpeg;\nusing Reactive.Bindings;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FFmpegCodecsViewModel : NotifyPropertyChanged\n    {\n        public FFmpegSettings Settings { get; }\n\n        public FFmpegCodecsViewModel(FFmpegSettings Settings)\n        {\n            this.Settings = Settings;\n\n            AddCustomCodecCommand = new ReactiveCommand()\n                .WithSubscribe(() => Settings.CustomCodecs.Add(new FFmpegCodecSettings()));\n\n            RemoveCustomCodecCommand = new ReactiveCommand<FFmpegCodecSettings>()\n                .WithSubscribe(M => Settings.CustomCodecs.Remove(M));\n        }\n\n        public ICommand AddCustomCodecCommand { get; }\n\n        public ICommand RemoveCustomCodecCommand { get; }\n\n        public IEnumerable<string> AudioCodecNames => FFmpegAudioItem.Items.Select(M => M.Name);\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/FFmpegLogViewModel.cs",
    "content": "﻿using System;\nusing System.Reactive.Linq;\nusing System.Windows.Input;\nusing Captura.FFmpeg;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FFmpegLogViewModel : NotifyPropertyChanged\n    {\n        public FFmpegLogViewModel(IClipboardService ClipboardService,\n            FFmpegLog FFmpegLog)\n        {\n            LogItems = FFmpegLog\n                .LogItems\n                .ToReadOnlyReactiveCollection();\n\n            LogItems\n                .ObserveAddChanged()\n                .Subscribe(M => SelectedLogItem = M);\n\n            LogItems\n                .ObserveRemoveChanged()\n                .Subscribe(M =>\n                {\n                    if (LogItems.Count > 0)\n                        SelectedLogItem = LogItems[0];\n                });\n\n            if (LogItems.Count > 0)\n                SelectedLogItem = LogItems[0];\n\n            CopyToClipboardCommand = this\n                .ObserveProperty(M => M.SelectedLogItem)\n                .Select(M => M != null)\n                .ToReactiveCommand()\n                .WithSubscribe(() =>\n                {\n                    ClipboardService.SetText(SelectedLogItem.GetCompleteLog());\n                });\n\n            RemoveCommand = this\n                .ObserveProperty(M => M.SelectedLogItem)\n                .Select(M => M != null)\n                .ToReactiveCommand()\n                .WithSubscribe(() => FFmpegLog.Remove(SelectedLogItem));\n        }\n\n        public ReadOnlyReactiveCollection<FFmpegLogItem> LogItems { get; }\n\n        FFmpegLogItem _selectedLogItem;\n\n        public FFmpegLogItem SelectedLogItem\n        {\n            get => _selectedLogItem;\n            set => Set(ref _selectedLogItem, value);\n        }\n\n        public ICommand CopyToClipboardCommand { get; }\n\n        public ICommand RemoveCommand { get; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/FFmpgDownloadViewModel.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Reactive.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Windows.Input;\nusing Captura.FFmpeg;\nusing Captura.Models;\nusing Reactive.Bindings;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FFmpegDownloadViewModel : NotifyPropertyChanged\n    {\n        public ICommand StartCommand { get; }\n\n        public ICommand SelectFolderCommand { get; }\n        public ICommand OpenFolderCommand { get; }\n\n        public IReadOnlyReactiveProperty<int> Progress { get; }\n        public IReadOnlyReactiveProperty<string> Status { get; }\n        public IReadOnlyReactiveProperty<bool> InProgress { get; }\n        public IReadOnlyReactiveProperty<bool> IsDone { get; }\n        public IReadOnlyReactiveProperty<bool> CanCancel { get; }\n\n        public FFmpegSettings FFmpegSettings { get; }\n\n        readonly IReactiveProperty<FFmpegDownloaderProgress> _downloaderProgress\n            = new ReactivePropertySlim<FFmpegDownloaderProgress>(\n                new FFmpegDownloaderProgress(FFmpegDownloaderState.Ready));\n\n        readonly IMessageProvider _messageProvider;\n        readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();\n\n        Task<bool> _downloadTask;\n\n        public FFmpegDownloadViewModel(FFmpegSettings FFmpegSettings,\n            FFmpegDownloadModel DownloadModel,\n            IFFmpegViewsProvider FFmpegViewsProvider,\n            IMessageProvider MessageProvider)\n        {\n            this.FFmpegSettings = FFmpegSettings;\n            _messageProvider = MessageProvider;\n\n            StartCommand = _downloaderProgress\n                .Select(M => M.State)\n                .Select(M => M == FFmpegDownloaderState.Ready)\n                .ToReactiveCommand()\n                .WithSubscribe(async () =>\n                {\n                    var progress = new Progress<FFmpegDownloaderProgress>(M => _downloaderProgress.Value = M);\n\n                    _downloadTask = DownloadModel.Start(progress, _cancellationTokenSource.Token);\n\n                    var result = await _downloadTask;\n\n                    AfterDownload?.Invoke(result);\n                });\n\n            CanCancel = _downloaderProgress\n                .Select(M => M.State)\n                .Select(M => M == FFmpegDownloaderState.Downloading)\n                .ToReadOnlyReactivePropertySlim();\n\n            SelectFolderCommand = _downloaderProgress\n                .Select(M => M.State)\n                .Select(M => M == FFmpegDownloaderState.Ready)\n                .ToReactiveCommand()\n                .WithSubscribe(FFmpegViewsProvider.PickFolder);\n\n            OpenFolderCommand = new ReactiveCommand()\n                .WithSubscribe(() =>\n                {\n                    var path = FFmpegSettings.GetFolderPath();\n\n                    if (Directory.Exists(path))\n                    {\n                        Process.Start(path);\n                    }\n                });\n\n            Status = _downloaderProgress\n                .Select(M =>\n                {\n                    switch (M.State)\n                    {\n                        case FFmpegDownloaderState.Error:\n                            return M.ErrorMessage;\n\n                        case FFmpegDownloaderState.Downloading:\n                            return $\"{FFmpegDownloaderState.Downloading} ({M.DownloadProgress}%)\";\n\n                        default:\n                            return M.State.ToString();\n                    }\n                })\n                .ToReadOnlyReactivePropertySlim();\n\n            Progress = _downloaderProgress\n                .Where(M => M.State == FFmpegDownloaderState.Downloading)\n                .Select(M => M.DownloadProgress)\n                .ToReadOnlyReactivePropertySlim();\n\n            Progress.Subscribe(M => ProgressChanged?.Invoke(M));\n\n            InProgress = _downloaderProgress\n                .Select(M => M.State)\n                .Select(M => M == FFmpegDownloaderState.Downloading || M == FFmpegDownloaderState.Extracting)\n                .ToReadOnlyReactivePropertySlim();\n\n            IsDone = _downloaderProgress\n                .Select(M => M.State)\n                .Select(M => M == FFmpegDownloaderState.Done || M == FFmpegDownloaderState.Cancelled || M == FFmpegDownloaderState.Error)\n                .ToReadOnlyReactivePropertySlim();\n        }\n\n        public event Action<int> ProgressChanged;\n        public event Action<bool> AfterDownload;\n\n        public async Task<bool> Cancel()\n        {\n            if (CanCancel.Value)\n            {\n                if (!_messageProvider.ShowYesNo(\"Are you sure you want to cancel download?\", \"Cancel Download\"))\n                    return false;\n\n                _cancellationTokenSource.Cancel();\n            }\n            else if (InProgress.Value)\n            {\n                return false;\n            }\n\n            _cancellationTokenSource.Dispose();\n\n            if (_downloadTask != null)\n            {\n                await _downloadTask;\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/FileNameFormatViewModel.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.IO;\nusing Captura.Loc;\nusing Captura.Models;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FileNameFormatViewModel : ViewModelBase\n    {\n        public FileNameFormatViewModel(Settings Settings, ILocalizationProvider Loc)\n            : base(Settings, Loc) { }\n\n        public IEnumerable<FileNameFormatGroup> FormatGroups { get; } = new []\n        {\n            new FileNameFormatGroup(\"Time\", new []\n            {\n                new FileNameFormatItem(\"%HH%\", \"Hours (24 hr) (20)\"),\n                new FileNameFormatItem(\"%hh%\", \"Hours (12 hr) (08)\"),\n                new FileNameFormatItem(\"%mm%\", \"Minutes (58)\"),\n                new FileNameFormatItem(\"%ss%\", \"Seconds (54)\"),\n                new FileNameFormatItem(\"%tt%\", \"AM / PM\"),\n                new FileNameFormatItem(\"%zzz%\", \"Time Zone (+05:30)\")\n            }),\n            new FileNameFormatGroup(\"Year\", new []\n            {\n                new FileNameFormatItem(\"%yyyy%\", \"Year (2018)\"),\n                new FileNameFormatItem(\"%yy%\", \"Year (18)\")\n            }),\n            new FileNameFormatGroup(\"Month\", new []\n            {\n                new FileNameFormatItem(\"%MMMM%\", \"Month (September)\"),\n                new FileNameFormatItem(\"%MMM%\", \"Month (Sep)\"),\n                new FileNameFormatItem(\"%MM%\", \"Month (09)\")\n            }),\n            new FileNameFormatGroup(\"Date\", new []\n            {\n                new FileNameFormatItem(\"%dd%\", \"Date (22)\"),\n                new FileNameFormatItem(\"%ddd%\", \"Day (Tue)\"),\n                new FileNameFormatItem(\"%dddd%\", \"Day (Tuesday)\")\n            }),\n            new FileNameFormatGroup(\"Other\", new []\n            {\n                new FileNameFormatItem(\"%computer%\", \"Company Name\"), \n                new FileNameFormatItem(\"%user%\", \"User Name\")\n            }), \n        };\n\n        public string FilenameFormat\n        {\n            get => Settings.FilenameFormat;\n            set\n            {\n                var invalidChars = Path.GetInvalidFileNameChars();\n\n                foreach (var invalidChar in invalidChars)\n                {\n                    if (invalidChar == '/' || invalidChar == '\\\\')\n                        continue;\n\n                    value = value.Replace(invalidChar.ToString(), \"\");\n                }\n\n                Settings.FilenameFormat = value;\n\n                OnPropertyChanged();\n\n                RaisePropertyChanged(nameof(FilenamePreview));\n            }\n        }\n\n        public string FilenamePreview => Settings.GetFileName(\".mp4\");\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/HotkeysViewModel.cs",
    "content": "﻿using System.Collections.ObjectModel;\nusing System.Windows.Input;\nusing Captura.Hotkeys;\nusing Reactive.Bindings;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class HotkeysViewModel\n    {\n        public ReadOnlyObservableCollection<Hotkey> Hotkeys { get; }\n\n        public HotkeysViewModel(HotKeyManager HotKeyManager)\n        {\n            Hotkeys = HotKeyManager.Hotkeys;\n\n            ResetCommand = new ReactiveCommand()\n                .WithSubscribe(HotKeyManager.Reset);\n\n            AddCommand = new ReactiveCommand()\n                .WithSubscribe(HotKeyManager.Add);\n\n            RemoveCommand = new ReactiveCommand()\n                .WithSubscribe(M =>\n                {\n                    if (M is Hotkey hotkey)\n                    {\n                        HotKeyManager.Remove(hotkey);\n                    }\n                });\n        }\n\n        public ICommand ResetCommand { get; }\n\n        public ICommand AddCommand { get; }\n\n        public ICommand RemoveCommand { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/LicensesViewModel.cs",
    "content": "﻿using System.IO;\nusing System.Linq;\nusing Captura.Models;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class LicensesViewModel : NotifyPropertyChanged\n    {\n        public LicensesViewModel()\n        {\n            var folder = Path.Combine(ServiceProvider.AppDir, \"licenses\");\n\n            if (Directory.Exists(folder))\n            {\n                Licenses = Directory.EnumerateFiles(folder).Select(FileName => new FileContentItem(FileName)).ToArray();\n\n                if (Licenses.Length > 0)\n                {\n                    SelectedLicense = Licenses[0];\n                }\n            }\n        }\n\n        public FileContentItem[] Licenses { get; }\n\n        FileContentItem _selectedLicense;\n\n        public FileContentItem SelectedLicense\n        {\n            get => _selectedLicense;\n            set => Set(ref _selectedLicense, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/MainViewModel.cs",
    "content": "﻿using Captura.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Reactive.Linq;\nusing System.Windows.Input;\nusing Captura.FFmpeg;\nusing Captura.Hotkeys;\nusing Captura.Loc;\nusing Captura.Video;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class MainViewModel : ViewModelBase, IDisposable\n    {\n        bool _persist;\n\n        readonly RememberByName _rememberByName;\n        readonly IDialogService _dialogService;\n\n        public ICommand ShowPreviewCommand { get; }\n        public ICommand OpenOutputFolderCommand { get; }\n        public ICommand SelectOutputFolderCommand { get; }\n        public ICommand SelectFFmpegFolderCommand { get; }\n        public ICommand ResetFFmpegFolderCommand { get; }\n        public ICommand TrayLeftClickCommand { get; }\n\n        public IReadOnlyReactiveProperty<string> OutFolderDisplay { get; }\n\n        public MainViewModel(Settings Settings,\n            ILocalizationProvider Loc,\n            HotKeyManager HotKeyManager,\n            IPreviewWindow PreviewWindow,\n            IDialogService DialogService,\n            RecordingModel RecordingModel,\n            IFFmpegViewsProvider FFmpegViewsProvider,\n            RememberByName RememberByName) : base(Settings, Loc)\n        {\n            _dialogService = DialogService;\n            _rememberByName = RememberByName;\n\n            OutFolderDisplay = Settings\n                .ObserveProperty(M => M.OutPath)\n                .Select(M => Settings.GetOutputPath())\n                .ToReadOnlyReactivePropertySlim();\n\n            ShowPreviewCommand = new ReactiveCommand()\n                .WithSubscribe(PreviewWindow.Show);\n\n            SelectFFmpegFolderCommand = new ReactiveCommand()\n                .WithSubscribe(FFmpegViewsProvider.PickFolder);\n\n            #region Commands\n            OpenOutputFolderCommand = new ReactiveCommand()\n                .WithSubscribe(OpenOutputFolder);\n\n            SelectOutputFolderCommand = new ReactiveCommand()\n                .WithSubscribe(SelectOutputFolder);\n\n            ResetFFmpegFolderCommand = new ReactiveCommand()\n                .WithSubscribe(() => Settings.FFmpeg.FolderPath = \"\");\n\n            TrayLeftClickCommand = new ReactiveCommand()\n                .WithSubscribe(() => HotKeyManager.FakeHotkey(Settings.Tray.LeftClickAction));\n            #endregion\n        }\n\n        public void Init(bool Persist, bool Remembered)\n        {\n            _persist = Persist;\n\n            if (Remembered)\n            {\n                _rememberByName.RestoreRemembered();\n            }\n        }\n\n        public static IEnumerable<ObjectLocalizer<Alignment>> XAlignments { get; } = new[]\n        {\n            new ObjectLocalizer<Alignment>(Alignment.Start, nameof(ILocalizationProvider.Left)),\n            new ObjectLocalizer<Alignment>(Alignment.Center, nameof(ILocalizationProvider.Center)),\n            new ObjectLocalizer<Alignment>(Alignment.End, nameof(ILocalizationProvider.Right))\n        };\n\n        public static IEnumerable<ObjectLocalizer<Alignment>> YAlignments { get; } = new[]\n        {\n            new ObjectLocalizer<Alignment>(Alignment.Start, nameof(ILocalizationProvider.Top)),\n            new ObjectLocalizer<Alignment>(Alignment.Center, nameof(ILocalizationProvider.Center)),\n            new ObjectLocalizer<Alignment>(Alignment.End, nameof(ILocalizationProvider.Bottom))\n        };\n\n        void OpenOutputFolder()\n        {\n            Process.Start(Settings.GetOutputPath());\n        }\n\n        void SelectOutputFolder()\n        {\n            string currentFolder = null;\n\n            try\n            {\n                currentFolder = Settings.GetOutputPath();\n            }\n            catch\n            {\n                // Error can happen if current folder is inaccessible\n            }\n\n            var folder = _dialogService.PickFolder(currentFolder, Loc.SelectOutFolder);\n\n            if (folder != null)\n                Settings.OutPath = folder;\n        }\n\n        public void Dispose()\n        {\n            // Remember things if not console.\n            if (!_persist)\n                return;\n\n            _rememberByName.Remember();\n\n            Settings.Save();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/OverlayListViewModel.cs",
    "content": "﻿using System.Collections.ObjectModel;\nusing System.Windows.Input;\nusing Reactive.Bindings;\n\nnamespace Captura.ViewModels\n{\n    public abstract class OverlayListViewModel<T> : NotifyPropertyChanged where T : class, new()\n    {\n        protected OverlayListViewModel(ObservableCollection<T> Collection)\n        {\n            _collection = Collection;\n\n            this.Collection = new ReadOnlyObservableCollection<T>(_collection);\n\n            AddCommand = new ReactiveCommand()\n                .WithSubscribe(OnAddExecute);\n\n            RemoveCommand = new ReactiveCommand()\n                .WithSubscribe(OnRemoveExecute);\n\n            if (Collection.Count > 0)\n            {\n                SelectedItem = Collection[0];\n            }\n        }\n\n        void OnAddExecute()\n        {\n            var item = new T();\n\n            _collection.Add(item);\n\n            SelectedItem = item;\n        }\n\n        void OnRemoveExecute(object O)\n        {\n            if (O is T setting)\n            {\n                _collection.Remove(setting);\n            }\n\n            SelectedItem = _collection.Count > 0 ? _collection[0] : null;\n        }\n\n        readonly ObservableCollection<T> _collection;\n\n        public ReadOnlyObservableCollection<T> Collection { get; }\n\n        public ICommand AddCommand { get; }\n\n        public ICommand RemoveCommand { get; }\n\n        T _selectedItem;\n\n        public T SelectedItem\n        {\n            get => _selectedItem;\n            set => Set(ref _selectedItem, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/ProxySettingsViewModel.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Reactive.Linq;\nusing Captura.Loc;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ProxySettingsViewModel : ViewModelBase\n    {\n        public ProxySettingsViewModel(Settings Settings, ILocalizationProvider Loc)\n            : base(Settings, Loc)\n        {\n            CanAuth = ProxySettings\n                .ObserveProperty(M => M.Type)\n                .Select(M => M != ProxyType.None)\n                .ToReadOnlyReactivePropertySlim();\n\n            CanAuthCred = new[]\n                {\n                    CanAuth,\n                    ProxySettings.ObserveProperty(M => M.Authenticate)\n                }\n                .CombineLatestValuesAreAllTrue()\n                .ToReadOnlyReactivePropertySlim();\n\n            CanHost = ProxySettings\n                .ObserveProperty(M => M.Type)\n                .Select(M => M == ProxyType.Manual)\n                .ToReadOnlyReactivePropertySlim();\n        }\n\n        public ProxySettings ProxySettings => Settings.Proxy;\n\n        public IReadOnlyReactiveProperty<bool> CanAuth { get; }\n\n        public IReadOnlyReactiveProperty<bool> CanAuthCred { get; }\n\n        public IReadOnlyReactiveProperty<bool> CanHost { get; }\n\n        public IEnumerable<ProxyType> ProxyTypes { get; } = new[] { ProxyType.None, ProxyType.System, ProxyType.Manual };\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/RecentViewModel.cs",
    "content": "﻿using Captura.Models;\nusing System.Collections.ObjectModel;\nusing System.Windows.Input;\nusing Captura.Loc;\nusing Reactive.Bindings;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class RecentViewModel : ViewModelBase\n    {\n        public ReadOnlyObservableCollection<IRecentItem> Items { get; }\n\n        public ICommand ClearCommand { get; }\n\n        public RecentViewModel(Settings Settings,\n            ILocalizationProvider Loc,\n            IRecentList Recent)\n            : base(Settings, Loc)\n        {\n            Items = Recent.Items;\n\n            ClearCommand = new ReactiveCommand()\n                .WithSubscribe(Recent.Clear);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/RecordingViewModel.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reactive.Linq;\nusing System.Threading.Tasks;\nusing System.Windows.Input;\nusing Captura.Audio;\nusing Captura.FFmpeg;\nusing Captura.Loc;\nusing Captura.Models;\nusing Captura.Video;\nusing Captura.Webcam;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class RecordingViewModel : ViewModelBase\n    {\n        readonly RecordingModel _recordingModel;\n        readonly TimerModel _timerModel;\n        readonly VideoSourcesViewModel _videoSourcesViewModel;\n        readonly VideoWritersViewModel _videoWritersViewModel;\n        readonly ISystemTray _systemTray;\n        readonly IMainWindow _mainWindow;\n        readonly IAudioPlayer _audioPlayer;\n        readonly IRecentList _recentList;\n        readonly IMessageProvider _messageProvider;\n        readonly AudioSourceViewModel _audioSourceViewModel;\n        readonly IFFmpegViewsProvider _ffmpegViewsProvider;\n\n        readonly SyncContextManager _syncContext = new SyncContextManager();\n\n        public ICommand RecordCommand { get; }\n        public ICommand PauseCommand { get; }\n\n        public RecordingViewModel(RecordingModel RecordingModel,\n            Settings Settings,\n            TimerModel TimerModel,\n            WebcamModel WebcamModel,\n            VideoSourcesViewModel VideoSourcesViewModel,\n            VideoWritersViewModel VideoWritersViewModel,\n            ISystemTray SystemTray,\n            IMainWindow MainWindow,\n            ILocalizationProvider Loc,\n            IAudioPlayer AudioPlayer,\n            IRecentList RecentList,\n            IMessageProvider MessageProvider,\n            AudioSourceViewModel AudioSourceViewModel,\n            IFFmpegViewsProvider FFmpegViewsProvider) : base(Settings, Loc)\n        {\n            _recordingModel = RecordingModel;\n            _timerModel = TimerModel;\n            _videoSourcesViewModel = VideoSourcesViewModel;\n            _videoWritersViewModel = VideoWritersViewModel;\n            _systemTray = SystemTray;\n            _mainWindow = MainWindow;\n            _audioPlayer = AudioPlayer;\n            _recentList = RecentList;\n            _messageProvider = MessageProvider;\n            _audioSourceViewModel = AudioSourceViewModel;\n            _ffmpegViewsProvider = FFmpegViewsProvider;\n\n            var hasAudio = new[]\n            {\n                Settings\n                    .Audio\n                    .ObserveProperty(M => M.RecordMicrophone),\n                Settings\n                    .Audio\n                    .ObserveProperty(M => M.RecordSpeaker)\n            }\n            .CombineLatest(M => M[0] || M[1]);            \n\n            RecordCommand = new[]\n                {\n                    hasAudio,\n                    VideoSourcesViewModel\n                        .ObserveProperty(M => M.SelectedVideoSourceKind)\n                        .Select(M => M is NoVideoSourceProvider),\n                    VideoSourcesViewModel\n                        .ObserveProperty(M => M.SelectedVideoSourceKind)\n                        .Select(M => M is WebcamSourceProvider),\n                    WebcamModel\n                        .ObserveProperty(M => M.SelectedCam)\n                        .Select(M => M is NoWebcamItem),\n                    Settings\n                        .Video\n                        .ObserveProperty(M => M.RecorderMode)\n                        .Select(M => M == RecorderMode.Steps),\n                    VideoSourcesViewModel\n                        .ObserveProperty(M => M.SelectedVideoSourceKind)\n                        .Select(M => M.SupportsStepsMode),\n                }\n                .CombineLatest(M =>\n                {\n                    var audioEnabled = M[0];\n                    var audioOnlyMode = M[1];\n                    var webcamMode = M[2];\n                    var noWebcam = M[3];\n                    var stepsMode = M[4];\n                    var supportsStepsMode = M[5];\n\n                    if (stepsMode)\n                        return supportsStepsMode;\n\n                    if (audioOnlyMode)\n                        return audioEnabled;\n\n                    if (webcamMode)\n                        return !noWebcam;\n\n                    return true;\n                })\n                .ToReactiveCommand()\n                .WithSubscribe(OnRecordExecute);\n\n            PauseCommand = new[]\n                {\n                    TimerModel\n                        .ObserveProperty(M => M.Waiting),\n                    RecordingModel\n                        .ObserveProperty(M => M.RecorderState)\n                        .Select(M => M != Models.RecorderState.NotRecording)\n                }\n                .CombineLatest(M => !M[0] && M[1])\n                .ToReactiveCommand()\n                .WithSubscribe(() =>\n                {\n                    _audioPlayer.Play(SoundKind.Pause);\n\n                    RecordingModel.OnPauseExecute();\n                });\n\n            RecorderState = RecordingModel\n                .ObserveProperty(M => M.RecorderState)\n                .ToReadOnlyReactivePropertySlim();\n            \n            TimerModel.DurationElapsed += () =>\n            {\n                _syncContext.Run(async () => await StopRecording(), true);\n            };\n        }\n\n        async void OnRecordExecute()\n        {\n            if (RecorderState.Value == Models.RecorderState.NotRecording)\n            {\n                StartRecording();\n            }\n            else await StopRecording();\n        }\n\n        readonly object _stopRecTaskLock = new object();\n        readonly List<Task> _stopRecTasks = new List<Task>();\n\n        int RunningStopRecordingCount\n        {\n            get\n            {\n                lock (_stopRecTaskLock)\n                {\n                    return _stopRecTasks.Count(M => !M.IsCompleted);\n                }\n            }\n        }\n\n        async Task StopRecording()\n        {\n            _audioPlayer.Play(SoundKind.Stop);\n\n            FileRecentItem savingRecentItem = null;\n            FileSaveNotification notification = null;\n\n            var fileName = _recordingModel.CurrentFileName;\n            var isVideo = _recordingModel.IsVideo;\n\n            IVideoConverter postWriter = null;\n\n            // Assume saving to file only when extension is present\n            if (!_timerModel.Waiting && !string.IsNullOrWhiteSpace(_videoWritersViewModel.SelectedVideoWriter.Extension))\n            {\n                savingRecentItem = new FileRecentItem(fileName, isVideo ? RecentFileType.Video : RecentFileType.Audio, true);\n                _recentList.Add(savingRecentItem);\n\n                notification = new FileSaveNotification(savingRecentItem);\n\n                notification.OnDelete += () => savingRecentItem.RemoveCommand.ExecuteIfCan();\n\n                _systemTray.ShowNotification(notification);\n\n                if (isVideo && Settings.Video.PostConvert)\n                    postWriter = _videoWritersViewModel.SelectedPostWriter;\n            }\n\n            var task = _recordingModel.StopRecording();\n\n            lock (_stopRecTaskLock)\n            {\n                _stopRecTasks.Add(task);\n            }\n\n            var wasWaiting = _timerModel.Waiting;\n            _timerModel.Waiting = false;\n\n            try\n            {\n                // Ensure saved\n                await task;\n\n                if (postWriter != null)\n                {\n                    notification.Converting();\n\n                    var progress = new Progress<int>();\n\n                    progress.ProgressChanged += (S, E) => notification.Progress = E;\n\n                    var outFileName = Path.Combine(\n                        Path.GetDirectoryName(fileName),\n                        $\"{Path.GetFileNameWithoutExtension(fileName)}.converted{postWriter.Extension}\");\n\n                    try\n                    {\n                        await postWriter.StartAsync(new VideoConverterArgs\n                        {\n                            AudioQuality = Settings.Audio.Quality,\n                            VideoQuality = Settings.Video.Quality,\n                            InputFile = fileName,\n                            FileName = outFileName\n                        }, progress);\n\n                        File.Delete(fileName);\n\n                        var targetFileName = Path.Combine(\n                            Path.GetDirectoryName(fileName),\n                            $\"{Path.GetFileNameWithoutExtension(fileName)}{postWriter.Extension}\");\n\n                        File.Move(outFileName, targetFileName);\n\n                        savingRecentItem.Converted(targetFileName);\n                        notification.Converted(targetFileName);\n                    }\n                    catch (FFmpegNotFoundException e)\n                    {\n                        try\n                        {\n                            _ffmpegViewsProvider.ShowUnavailable();\n                        }\n                        catch\n                        {\n                            // Show simpler message for cases the above fails\n                            _messageProvider.ShowException(e, e.Message);\n                        }\n                    }\n                    catch (Exception e)\n                    {\n                        _messageProvider.ShowException(e, \"Conversion Failed\");\n                    }                    \n                }\n\n                lock (_stopRecTaskLock)\n                {\n                    _stopRecTasks.Remove(task);\n                }\n            }\n            catch (Exception e)\n            {\n                _messageProvider.ShowException(e, \"Error occurred when stopping recording.\\nThis might sometimes occur if you stop recording just as soon as you start it.\");\n\n                return;\n            }\n\n            if (wasWaiting)\n            {\n                try\n                {\n                    File.Delete(fileName);\n                }\n                catch\n                {\n                    // Ignore Errors\n                }\n            }\n\n            if (savingRecentItem != null)\n            {\n                AfterSave(savingRecentItem, notification);\n            }\n        }\n\n        void AfterSave(FileRecentItem SavingRecentItem, FileSaveNotification Notification)\n        {\n            SavingRecentItem.Saved();\n\n            if (Settings.CopyOutPathToClipboard)\n                SavingRecentItem.FileName.WriteToClipboard();\n\n            Notification.Saved();\n        }\n\n        void StartRecording()\n        {\n            _systemTray.HideNotification();\n\n            if (_recordingModel.StartRecording(new RecordingModelParams\n            {\n                VideoSourceKind = _videoSourcesViewModel.SelectedVideoSourceKind,\n                VideoWriter = Settings.Video.RecorderMode == RecorderMode.Steps\n                    ? _videoWritersViewModel.SelectedStepsWriter\n                    : _videoWritersViewModel.SelectedVideoWriter,\n                Microphone = Settings.Audio.RecordMicrophone ? _audioSourceViewModel.SelectedMicrophone : null,\n                Speaker = Settings.Audio.RecordSpeaker ? _audioSourceViewModel.SelectedSpeaker : null\n            }))\n            {\n                if (Settings.Tray.MinToTrayOnCaptureStart)\n                    _mainWindow.IsVisible = false;\n\n                _audioPlayer.Play(SoundKind.Start);\n            }\n            else _audioPlayer.Play(SoundKind.Error);\n        }\n\n        public IReadOnlyReactiveProperty<RecorderState> RecorderState { get; }\n\n        public bool CanExit()\n        {\n            if (RecorderState.Value == Models.RecorderState.Recording)\n            {\n                if (!_messageProvider.ShowYesNo(\n                    \"A Recording is in progress. Are you sure you want to exit?\", \"Confirm Exit\"))\n                    return false;\n            }\n            else if (RunningStopRecordingCount > 0)\n            {\n                if (!_messageProvider.ShowYesNo(\n                    \"Some Recordings have not finished writing to disk. Are you sure you want to exit?\", \"Confirm Exit\"))\n                    return false;\n            }\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/ScreenShotViewModel.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reactive.Linq;\nusing System.Threading.Tasks;\nusing System.Windows.Input;\nusing Captura.Loc;\nusing Captura.Models;\nusing Captura.Video;\nusing Captura.Webcam;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ScreenShotViewModel : ViewModelBase\n    {\n        public DiskWriter DiskWriter { get; }\n        public ClipboardWriter ClipboardWriter { get; }\n        public ImageUploadWriter ImgurWriter { get; }\n\n        public ScreenShotViewModel(ILocalizationProvider Loc,\n            Settings Settings,\n            DiskWriter DiskWriter,\n            ClipboardWriter ClipboardWriter,\n            ImageUploadWriter ImgurWriter,\n            ScreenShotModel ScreenShotModel,\n            VideoSourcesViewModel VideoSourcesViewModel,\n            WebcamModel WebcamModel,\n            IPlatformServices PlatformServices) : base(Settings, Loc)\n        {\n            this.DiskWriter = DiskWriter;\n            this.ClipboardWriter = ClipboardWriter;\n            this.ImgurWriter = ImgurWriter;\n\n            ScreenShotCommand = new[]\n                {\n                    VideoSourcesViewModel\n                        .ObserveProperty(M => M.SelectedVideoSourceKind)\n                        .Select(M => M is NoVideoSourceProvider),\n                    VideoSourcesViewModel\n                        .ObserveProperty(M => M.SelectedVideoSourceKind)\n                        .Select(M => M is WebcamSourceProvider),\n                    WebcamModel\n                        .ObserveProperty(M => M.SelectedCam)\n                        .Select(M => M is NoWebcamItem)\n                }\n                .CombineLatest(M =>\n                {\n                    var noVideo = M[0];\n                    var webcamMode = M[1];\n                    var noWebcam = M[2];\n\n                    if (webcamMode)\n                        return !noWebcam;\n\n                    return !noVideo;\n                })\n                .ToReactiveCommand()\n                .WithSubscribe(async M =>\n                {\n                    var bmp = await ScreenShotModel.GetScreenShot(VideoSourcesViewModel.SelectedVideoSourceKind);\n\n                    await ScreenShotModel.SaveScreenShot(bmp);\n                });\n\n            async Task ScreenShotWindow(IWindow Window)\n            {\n                var img = ScreenShotModel.ScreenShotWindow(Window);\n\n                await ScreenShotModel.SaveScreenShot(img);\n            }\n\n            ScreenShotActiveCommand = new ReactiveCommand()\n                .WithSubscribe(async () => await ScreenShotWindow(PlatformServices.ForegroundWindow));\n\n            ScreenShotDesktopCommand = new ReactiveCommand()\n                .WithSubscribe(async () =>\n                {\n                    await Task.Delay(300);\n\n                    await ScreenShotWindow(PlatformServices.DesktopWindow);\n                });\n\n            ScreenshotRegionCommand = new ReactiveCommand()\n                .WithSubscribe(async () =>\n                {\n                    await Task.Delay(300);\n\n                    await ScreenShotModel.ScreenshotRegion();\n                });\n\n            ScreenshotWindowCommand = new ReactiveCommand()\n                .WithSubscribe(async () =>\n                {\n                    await Task.Delay(300);\n\n                    await ScreenShotModel.ScreenshotWindow();\n                });\n\n            ScreenshotScreenCommand = new ReactiveCommand()\n                .WithSubscribe(async () =>\n                {\n                    await Task.Delay(300);\n\n                    await ScreenShotModel.ScreenshotScreen();\n                });\n        }\n\n        public ICommand ScreenShotCommand { get; }\n        public ICommand ScreenShotActiveCommand { get; }\n        public ICommand ScreenShotDesktopCommand { get; }\n        public ICommand ScreenshotRegionCommand { get; }\n        public ICommand ScreenshotWindowCommand { get; }\n        public ICommand ScreenshotScreenCommand { get; }\n\n        public IEnumerable<ImageFormats> ScreenShotImageFormats { get; } = Enum\n            .GetValues(typeof(ImageFormats))\n            .Cast<ImageFormats>();\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/SoundsViewModel.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing Captura.Audio;\nusing Captura.Models;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class SoundsViewModel : NotifyPropertyChanged\n    {\n        public IReadOnlyCollection<SoundsViewModelItem> Items { get; }\n\n        public SoundsViewModel(IDialogService DialogService, SoundSettings Settings)\n        {\n            Items = new[]\n            {\n                SoundKind.Start,\n                SoundKind.Stop,\n                SoundKind.Pause,\n                SoundKind.Shot,\n                SoundKind.Error,\n                SoundKind.Notification\n            }.Select(Kind => new SoundsViewModelItem(Kind, DialogService, Settings)).ToList();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/UpdateCheckerViewModel.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing System.Windows.Input;\nusing Captura.Models;\nusing Reactive.Bindings;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class UpdateCheckerViewModel : NotifyPropertyChanged\n    {\n        readonly IUpdateChecker _updateChecker;\n\n        public UpdateCheckerViewModel(IUpdateChecker UpdateChecker)\n        {\n            _updateChecker = UpdateChecker;\n            BuildName = UpdateChecker.BuildName;\n\n            Check();\n\n            CheckCommand = new ReactiveCommand()\n                .WithSubscribe(Check);\n\n            GoToDownload = new ReactiveCommand()\n                .WithSubscribe(UpdateChecker.GoToDownloadsPage);\n        }\n\n        public string BuildName { get; }\n\n        void Check()\n        {\n            if (Checking)\n                return;\n\n            Checking = true;\n            UpdateAvailable = false;\n            CheckFailed = false;\n\n            Task.Run(async () =>\n            {\n                try\n                {\n                    var newVersion = await _updateChecker.Check();\n\n                    if (newVersion != null)\n                    {\n                        UpdateAvailable = true;\n\n                        NewVersion = \"v\" + newVersion;\n                    }\n                }\n                catch (Exception e)\n                {\n                    Console.WriteLine(e.ToString());\n\n                    CheckFailed = true;\n                }\n                finally\n                {\n                    Checking = false;\n                }\n            });\n        }\n\n        bool _checking, _available, _checkFailed;\n\n        public bool Checking\n        {\n            get => _checking;\n            private set => Set(ref _checking, value);\n        }\n\n        public bool UpdateAvailable\n        {\n            get => _available;\n            private set => Set(ref _available, value);\n        }\n\n        public bool CheckFailed\n        {\n            get => _checkFailed;\n            private set => Set(ref _checkFailed, value);\n        }\n\n        string _newVersion;\n\n        public string NewVersion\n        {\n            get => _newVersion;\n            private set => Set(ref _newVersion, value);\n        }\n\n        public ICommand CheckCommand { get; }\n\n        public ICommand GoToDownload { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/VideoSourcesViewModel.cs",
    "content": "using System.Collections.Generic;\nusing Captura.Video;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class VideoSourcesViewModel : NotifyPropertyChanged\n    {\n        readonly FullScreenSourceProvider _fullScreenProvider;\n        readonly Settings _settings;\n        public NoVideoSourceProvider NoVideoSourceProvider { get; }\n\n        public IEnumerable<IVideoSourceProvider> VideoSources { get; }\n\n        public VideoSourcesViewModel(FullScreenSourceProvider FullScreenProvider,\n            NoVideoSourceProvider NoVideoSourceProvider,\n            IEnumerable<IVideoSourceProvider> SourceProviders,\n            Settings Settings)\n        {\n            this.NoVideoSourceProvider = NoVideoSourceProvider;\n            _fullScreenProvider = FullScreenProvider;\n            _settings = Settings;\n            VideoSources = SourceProviders;\n\n            SetDefaultSource();\n        }\n\n        public void SetDefaultSource()\n        {\n            SelectedVideoSourceKind = _fullScreenProvider;\n        }\n\n        void ChangeSource(IVideoSourceProvider NewSourceProvider, bool CallOnSelect)\n        {\n            try\n            {\n                if (NewSourceProvider == null || _videoSourceKind == NewSourceProvider)\n                    return;\n\n                // Doesn't support Steps mode\n                if (_settings.Video.RecorderMode == RecorderMode.Steps && !NewSourceProvider.SupportsStepsMode)\n                    return;\n\n                if (CallOnSelect && !NewSourceProvider.OnSelect())\n                {\n                    return;\n                }\n\n                _videoSourceKind?.OnUnselect();\n\n                _videoSourceKind = NewSourceProvider;\n            }\n            finally\n            {\n                // Delay parameter needs to be used with Binding for handling cancellation\n                RaisePropertyChanged(nameof(SelectedVideoSourceKind));\n            }\n        }\n\n        IVideoSourceProvider _videoSourceKind;\n\n        public IVideoSourceProvider SelectedVideoSourceKind\n        {\n            get => _videoSourceKind;\n            set => ChangeSource(value, true);\n        }\n\n        public void RestoreSourceKind(IVideoSourceProvider SourceProvider)\n        {\n            ChangeSource(SourceProvider, false);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/VideoWritersViewModel.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing System;\nusing Captura.SharpAvi;\nusing Captura.Video;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class VideoWritersViewModel : NotifyPropertyChanged\n    {\n        public IReadOnlyList<IVideoWriterProvider> VideoWriterProviders { get; }\n        readonly ObservableCollection<IVideoWriterItem> _videoWriters = new ObservableCollection<IVideoWriterItem>();\n        public ReadOnlyObservableCollection<IVideoWriterItem> AvailableVideoWriters { get; }\n\n        public IEnumerable<IVideoConverter> AvailablePostWriters { get; }\n\n        public VideoWritersViewModel(IEnumerable<IVideoWriterProvider> WriterProviders,\n            IEnumerable<IVideoConverter> PostWriters,\n            SharpAviWriterProvider SharpAviWriterProvider)\n        {\n            VideoWriterProviders = WriterProviders.ToList();\n\n            AvailableVideoWriters = new ReadOnlyObservableCollection<IVideoWriterItem>(_videoWriters);\n\n            AvailablePostWriters = PostWriters;\n            SelectedPostWriter = PostWriters.FirstOrDefault();\n\n            if (VideoWriterProviders.Count > 0)\n                SelectedVideoWriterKind = VideoWriterProviders[0];\n\n            AvailableStepWriters = new IVideoWriterItem[]\n            {\n                new StepsVideoWriterItem(SharpAviWriterProvider.First()),\n                new ImageFolderWriterItem()\n            };\n\n            SelectedStepsWriter = AvailableStepWriters[0];\n        }\n\n        public void RefreshCodecs()\n        {\n            // Remember selected codec\n            var lastVideoCodecName = SelectedVideoWriter?.ToString();\n\n            _videoWriters.Clear();\n\n            foreach (var writerItem in SelectedVideoWriterKind)\n            {\n                _videoWriters.Add(writerItem);\n            }\n\n            // Set First\n            if (_videoWriters.Count > 0)\n                SelectedVideoWriter = _videoWriters[0];\n\n            var matchingVideoCodec = AvailableVideoWriters.FirstOrDefault(M => M.ToString() == lastVideoCodecName);\n\n            if (matchingVideoCodec != null)\n            {\n                SelectedVideoWriter = matchingVideoCodec;\n            }\n        }\n\n        IVideoWriterProvider _writerKind;\n\n        public IVideoWriterProvider SelectedVideoWriterKind\n        {\n            get => _writerKind;\n            set\n            {\n                if (_writerKind == value)\n                    return;\n\n                if (value != null)\n                    _writerKind = value;\n\n                OnPropertyChanged();\n\n                RefreshCodecs();\n            }\n        }\n\n        IVideoWriterItem _writer;\n\n        public IVideoWriterItem SelectedVideoWriter\n        {\n            get => _writer;\n            set => Set(ref _writer, value ?? AvailableVideoWriters.FirstOrDefault());\n        }\n\n        IVideoConverter _postWriter;\n\n        public IVideoConverter SelectedPostWriter\n        {\n            get => _postWriter;\n            set => Set(ref _postWriter, value ?? AvailablePostWriters.FirstOrDefault());\n        }\n\n        public IReadOnlyList<IVideoWriterItem> AvailableStepWriters { get; }\n\n        IVideoWriterItem _stepsWriter;\n\n        public IVideoWriterItem SelectedStepsWriter\n        {\n            get => _stepsWriter;\n            set => Set(ref _stepsWriter, value ?? AvailableStepWriters[0]);\n        }\n\n        public IEnumerable<RecorderMode> AvailableRecorderModes { get; } = Enum\n            .GetValues(typeof(RecorderMode))\n            .Cast<RecorderMode>();\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/ViewConditionsModel.cs",
    "content": "﻿using System.Reactive.Linq;\nusing System.Windows;\nusing Captura.FFmpeg;\nusing Captura.Models;\nusing Captura.Video;\nusing Captura.Webcam;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ViewConditionsModel\n    {\n        public ViewConditionsModel(VideoSourcesViewModel VideoSourcesViewModel,\n            VideoWritersViewModel VideoWritersViewModel,\n            Settings Settings,\n            RecordingModel RecordingModel,\n            AudioSourceViewModel AudioSourceViewModel)\n        {\n            IsRegionMode = VideoSourcesViewModel\n                .ObserveProperty(M => M.SelectedVideoSourceKind)\n                .Select(M => M is RegionSourceProvider)\n                .ToReadOnlyReactivePropertySlim();\n\n            IsAudioMode = VideoSourcesViewModel\n                .ObserveProperty(M => M.SelectedVideoSourceKind)\n                .Select(M => M is NoVideoSourceProvider)\n                .ToReadOnlyReactivePropertySlim();\n\n            IsStepsMode = Settings\n                .Video\n                .ObserveProperty(M => M.RecorderMode)\n                .Select(M => M == RecorderMode.Steps)\n                .ToReadOnlyReactivePropertySlim();\n\n            IsNotAudioOrStepsMode = new[]\n                {\n                    VideoSourcesViewModel\n                        .ObserveProperty(M => M.SelectedVideoSourceKind)\n                        .Select(M => M is NoVideoSourceProvider),\n                    IsStepsMode\n                }\n                .CombineLatest(M =>\n                {\n                    var audioMode = M[0];\n                    var stepsMode = M[1];\n\n                    return !audioMode && !stepsMode;\n                })\n                .ToReadOnlyReactivePropertySlim();\n\n            MultipleVideoWriters = VideoWritersViewModel.AvailableVideoWriters\n                .ObserveProperty(M => M.Count)\n                .Select(M => M > 1)\n                .ToReadOnlyReactivePropertySlim();\n\n            IsFFmpeg = VideoWritersViewModel\n                .ObserveProperty(M => M.SelectedVideoWriterKind)\n                .Select(M => M is FFmpegWriterProvider || M is StreamingWriterProvider)\n                .ToReadOnlyReactivePropertySlim();\n\n            IsVideoQuality = VideoWritersViewModel\n                .ObserveProperty(M => M.SelectedVideoWriterKind)\n                .Select(M => M is DiscardWriterProvider)\n                .Select(M => !M)\n                .ToReadOnlyReactivePropertySlim();\n\n            IsReplayMode = Settings\n                .Video\n                .ObserveProperty(M => M.RecorderMode)\n                .Select(M => M == RecorderMode.Replay)\n                .ToReadOnlyReactivePropertySlim();\n\n            CanChangeWebcam = new[]\n                {\n                    RecordingModel\n                        .ObserveProperty(M => M.RecorderState)\n                        .Select(M => M == RecorderState.NotRecording),\n                    Settings.WebcamOverlay\n                        .ObserveProperty(M => M.SeparateFile),\n                    VideoSourcesViewModel\n                        .ObserveProperty(M => M.SelectedVideoSourceKind)\n                        .Select(M => M is WebcamSourceProvider)\n                }\n                .CombineLatest(M =>\n                {\n                    var notRecording = M[0];\n                    var separateFile = M[1];\n                    var webcamMode = M[2];\n\n                    if (webcamMode)\n                    {\n                        return notRecording;\n                    }\n\n                    return !separateFile || notRecording;\n                })\n                .ToReadOnlyReactivePropertySlim();\n\n            IsEnabled = RecordingModel\n                .ObserveProperty(M => M.RecorderState)\n                .Select(M => M == RecorderState.NotRecording)\n                .ToReadOnlyReactivePropertySlim();\n\n            CanWebcamSeparateFile = VideoSourcesViewModel\n                .ObserveProperty(M => M.SelectedVideoSourceKind)\n                .Select(M => M is WebcamSourceProvider)\n                .Select(M => !M)\n                .ToReadOnlyReactivePropertySlim();\n\n            IsAroundMouseMode = VideoSourcesViewModel\n                .ObserveProperty(M => M.SelectedVideoSourceKind)\n                .Select(M => M is AroundMouseSourceProvider)\n                .ToReadOnlyReactivePropertySlim();\n\n            IsWebcamMode = VideoSourcesViewModel\n                .ObserveProperty(M => M.SelectedVideoSourceKind)\n                .Select(M => M is WebcamSourceProvider)\n                .ToReadOnlyReactivePropertySlim();\n\n            ShowSourceNameBox = VideoSourcesViewModel\n                .ObserveProperty(M => M.SelectedVideoSourceKind)\n                .Select(M => M is RegionSourceProvider || M is AroundMouseSourceProvider)\n                .Select(M => !M)\n                .ToReadOnlyReactivePropertySlim();\n\n            StepsBtnEnabled = new[]\n                {\n                    IsEnabled,\n                    VideoSourcesViewModel\n                        .ObserveProperty(M => M.SelectedVideoSourceKind)\n                        .Select(M => M.SupportsStepsMode)\n                }\n                .CombineLatestValuesAreAllTrue()\n                .ToReadOnlyReactivePropertySlim();\n\n            FpsVisibility = RecordingModel.ObserveProperty(M => M.RecorderState)\n                .CombineLatest(IsNotAudioOrStepsMode,\n                    (RecorderState, IsNotAudioOrStepsMode) => RecorderState == RecorderState.Recording && IsNotAudioOrStepsMode)\n                .Select(M => M ? Visibility.Visible : Visibility.Hidden)\n                .ToReadOnlyReactivePropertySlim();\n        }\n\n        public IReadOnlyReactiveProperty<bool> StepsBtnEnabled { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsNotAudioOrStepsMode { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsRegionMode { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsAudioMode { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsStepsMode { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsWebcamMode { get; }\n\n        public IReadOnlyReactiveProperty<bool> MultipleVideoWriters { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsFFmpeg { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsVideoQuality { get; }\n\n        public IReadOnlyReactiveProperty<bool> CanChangeWebcam { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsEnabled { get; }\n\n        public IReadOnlyReactiveProperty<bool> CanWebcamSeparateFile { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsAroundMouseMode { get; }\n\n        public IReadOnlyReactiveProperty<bool> IsReplayMode { get; }\n\n        public IReadOnlyReactiveProperty<bool> ShowSourceNameBox { get; }\n\n        public IReadOnlyReactiveProperty<Visibility> FpsVisibility { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.ViewCore/ViewModels/YouTubeUploaderViewModel.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Reactive.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Windows.Input;\nusing Captura.Models;\nusing Captura.YouTube;\nusing Google.Apis.Upload;\nusing Reactive.Bindings;\nusing Reactive.Bindings.Extensions;\n\nnamespace Captura.ViewModels\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class YouTubeUploaderViewModel : NotifyPropertyChanged\n    {\n        readonly YouTubeUploader _uploader;\n        readonly CancellationTokenSource _cancellationTokenSource;\n        readonly IMessageProvider _messageProvider;\n        Task _uploadTask;\n        string _fileName, _link, _title;\n        string _description = \"\\n\\n\\n\\n--------------------------------------------------\\n\\nUploaded using Captura (https://mathewsachin.github.io/Captura/)\";\n        YouTubePrivacyStatus _privacyStatus;\n        int _progress;\n        bool _beganUploading;\n        YouTubeUploadRequest _uploadRequest;\n\n        readonly IReactiveProperty<bool> _canUpload = new ReactivePropertySlim<bool>(true);\n\n        public YouTubeUploaderViewModel(YouTubeUploader Uploader,\n            IMessageProvider MessageProvider,\n            IClipboardService ClipboardService)\n        {\n            _uploader = Uploader;\n            _messageProvider = MessageProvider;\n            _cancellationTokenSource = new CancellationTokenSource();\n\n            OpenVideoCommand = this\n                .ObserveProperty(M => M.Link)\n                .Select(M => !string.IsNullOrWhiteSpace(M))\n                .ToReactiveCommand()\n                .WithSubscribe(() => Process.Start(Link));\n\n            CopyLinkCommand = this\n                .ObserveProperty(M => M.Link)\n                .Select(M => !string.IsNullOrWhiteSpace(M))\n                .ToReactiveCommand()\n                .WithSubscribe(() => ClipboardService.SetText(Link));\n\n            UploadCommand = new[]\n                {\n                    _canUpload,\n                    this.ObserveProperty(M => Title)\n                        .Select(M => !string.IsNullOrWhiteSpace(M))\n                }\n                .CombineLatestValuesAreAllTrue()\n                .ToReactiveCommand()\n                .WithSubscribe(() => _uploadTask = OnUpload());\n        }\n\n        public async Task Init(string FilePath)\n        {\n            FileName = FilePath;\n            Title = Path.GetFileName(FileName);\n\n            var fileSize = new FileInfo(FileName).Length;\n\n            _uploadRequest = await _uploader.CreateUploadRequest(FileName,\n                Title,\n                Description,\n                PrivacyStatus: PrivacyStatus);\n\n            _uploadRequest.Uploaded += L =>\n            {\n                Link = L;\n\n                CancelBtnText = \"Finish\";\n            };\n\n            _uploadRequest.BytesSent += B => Progress = (int)(B * 100 / fileSize);\n        }\n\n        async Task OnUpload()\n        {\n            _canUpload.Value = false;\n\n            var token = _cancellationTokenSource.Token;\n\n            var task = BeganUploading\n                ? _uploadRequest.Resume(token)\n                : _uploadRequest.Upload(token);\n\n            BeganUploading = true;\n\n            try\n            {\n                var result = await task;\n\n                if (result.Status == UploadStatus.Failed)\n                {\n                    _messageProvider.ShowException(result.Exception, \"Error Occured while Uploading\");\n\n                    _canUpload.Value = true;\n\n                    UploadBtnText = \"Retry\";\n                }\n            }\n            catch (TaskCanceledException)\n            {\n                // Cancelled by user\n            }\n        }\n\n        public async Task<bool> Cancel()\n        {\n            // Began Uploading but not finished\n            if (BeganUploading && Link == null)\n            {\n                if (!_messageProvider.ShowYesNo(\"Are you sure you want to cancel upload?\", \"Cancel Upload\"))\n                    return false;\n            }\n\n            using (_cancellationTokenSource)\n            using (_uploadRequest)\n            {\n                _cancellationTokenSource.Cancel();\n\n                if (_uploadTask != null)\n                    await _uploadTask;\n            }\n\n            return true;\n        }\n\n        public string FileName\n        {\n            get => _fileName;\n            private set => Set(ref _fileName, value);\n        }\n\n        public string Link\n        {\n            get => _link;\n            private set => Set(ref _link, value);\n        }\n\n        public string Title\n        {\n            get => _title;\n            set => Set(ref _title, value);\n        }\n\n        public string Description\n        {\n            get => _description;\n            set => Set(ref _description, value);\n        }\n\n        public YouTubePrivacyStatus PrivacyStatus\n        {\n            get => _privacyStatus;\n            set => Set(ref _privacyStatus, value);\n        }\n\n        public IEnumerable<YouTubePrivacyStatus> PrivacyStatuses { get; } = new[]\n        {\n            YouTubePrivacyStatus.Public,\n            YouTubePrivacyStatus.Unlisted,\n            YouTubePrivacyStatus.Private\n        };\n\n        public int Progress\n        {\n            get => _progress;\n            private set => Set(ref _progress, value);\n        }\n\n        public bool BeganUploading\n        {\n            get => _beganUploading;\n            private set => Set(ref _beganUploading, value);\n        }\n\n        public ICommand UploadCommand { get; }\n        public ICommand OpenVideoCommand { get; }\n        public ICommand CopyLinkCommand { get; }\n\n        string _uploadBtnText = \"Upload\", _cancelBtnText = \"Cancel\";\n\n        public string UploadBtnText\n        {\n            get => _uploadBtnText;\n            private set => Set(ref _uploadBtnText, value);\n        }\n\n        public string CancelBtnText\n        {\n            get => _cancelBtnText;\n            private set => Set(ref _cancelBtnText, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Captura.Windows.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net472</TargetFramework>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Reference Include=\"System.Windows.Forms\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"MediaFoundation\" Version=\"3.1.0\" />\n    <PackageReference Include=\"Ookii.Dialogs.WindowsForms\" Version=\"1.0.0\" />\n    <PackageReference Include=\"DirectShowLib\" Version=\"1.0.0\" />\n    <PackageReference Include=\"SharpDX.Direct2D1\" Version=\"4.2.0\" />\n    <PackageReference Include=\"SharpDX.Direct3D11\" Version=\"4.2.0\" />\n    <PackageReference Include=\"SharpDX.Direct3D9\" Version=\"4.2.0\" />\n    <PackageReference Include=\"SharpDX.MediaFoundation\" Version=\"4.2.0\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Captura.Windows/Capture/DxgiTargetDeviceContext.cs",
    "content": "﻿using System;\nusing Captura.Windows.DirectX;\nusing SharpDX.Direct3D11;\nusing SharpDX.DXGI;\n\nnamespace Captura.Video\n{\n    class DxgiTargetDeviceContext : ITargetDeviceContext\n    {\n        readonly Direct2DEditorSession _editorSession;\n        readonly Texture2D _gdiCompatibleTexture;\n        readonly Surface1 _dxgiSurface;\n\n        public DxgiTargetDeviceContext(IPreviewWindow PreviewWindow, int Width, int Height)\n        {\n            _editorSession = new Direct2DEditorSession(Width, Height, PreviewWindow);\n            _gdiCompatibleTexture = _editorSession.CreateGdiTexture(Width, Height);\n\n            _dxgiSurface = _gdiCompatibleTexture.QueryInterface<Surface1>();\n        }\n\n        public IBitmapFrame DummyFrame => Texture2DFrame.DummyFrame;\n\n        public void Dispose()\n        {\n            _dxgiSurface.Dispose();\n            _gdiCompatibleTexture.Dispose();\n            _editorSession.Dispose();\n        }\n\n        public IntPtr GetDC()\n        {\n            return _dxgiSurface.GetDC(true);\n        }\n\n        public IEditableFrame GetEditableFrame()\n        {\n            _dxgiSurface.ReleaseDC();\n\n            _editorSession.Device.ImmediateContext.CopyResource(_gdiCompatibleTexture, _editorSession.DesktopTexture);\n            _editorSession.Device.ImmediateContext.Flush();\n\n            return new Direct2DEditor(_editorSession);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Capture/GdiTargetDeviceContext.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Native;\nusing Captura.Video;\n\nnamespace Captura.Windows.Gdi\n{\n    class GdiTargetDeviceContext : ITargetDeviceContext\n    {\n        readonly IntPtr _hdcDest, _hBitmap;\n\n        public GdiTargetDeviceContext(IntPtr SrcDc, int Width, int Height)\n        {\n            _hdcDest = Gdi32.CreateCompatibleDC(SrcDc);\n            _hBitmap = Gdi32.CreateCompatibleBitmap(SrcDc, Width, Height);\n\n            Gdi32.SelectObject(_hdcDest, _hBitmap);\n        }\n\n        public IBitmapFrame DummyFrame => DrawingFrame.DummyFrame;\n\n        public void Dispose()\n        {\n            Gdi32.DeleteDC(_hdcDest);\n            Gdi32.DeleteObject(_hBitmap);\n        }\n\n        public IntPtr GetDC() => _hdcDest;\n\n        public IEditableFrame GetEditableFrame()\n        {\n            return new GraphicsEditor(Image.FromHbitmap(_hBitmap));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Capture/ITargetDeviceContext.cs",
    "content": "﻿using System;\n\nnamespace Captura.Video\n{\n    interface ITargetDeviceContext : IDisposable\n    {\n        IntPtr GetDC();\n\n        IBitmapFrame DummyFrame { get; }\n\n        IEditableFrame GetEditableFrame();\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Capture/MouseCursor.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Runtime.InteropServices;\nusing Captura.Native;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Draws the MouseCursor on an Image\n    /// </summary>\n    static class MouseCursor\n    {\n        const int CursorShowing = 1;\n        \n        /// <summary>\n        /// Draws this overlay.\n        /// </summary>\n        /// <param name=\"G\">A <see cref=\"Graphics\"/> object to draw upon.</param>\n        /// <param name=\"Transform\">Point Transform Function.</param>\n        public static void Draw(Graphics G, Func<Point, Point> Transform = null)\n        {\n            var hIcon = GetIcon(Transform, out var location);\n\n            if (hIcon == IntPtr.Zero)\n                return;\n\n            var bmp = Icon.FromHandle(hIcon).ToBitmap();\n            User32.DestroyIcon(hIcon);\n\n            try\n            {\n                using (bmp)\n                    G.DrawImage(bmp, new Rectangle(location, bmp.Size));\n            }\n            catch (ArgumentException) { }\n        }\n\n        public static void Draw(IntPtr DeviceContext, Func<Point, Point> Transform = null)\n        {\n            var hIcon = GetIcon(Transform, out var location);\n\n            if (hIcon == IntPtr.Zero)\n                return;\n\n            try\n            {\n                User32.DrawIconEx(DeviceContext,\n                    location.X, location.Y,\n                    hIcon,\n                    0, 0, 0, IntPtr.Zero,\n                    DrawIconExFlags.Normal);\n            }\n            finally\n            {\n                User32.DestroyIcon(hIcon);\n            }\n        }\n\n        static IntPtr GetIcon(Func<Point, Point> Transform, out Point Location)\n        {\n            Location = Point.Empty;\n\n            var cursorInfo = new CursorInfo {cbSize = Marshal.SizeOf<CursorInfo>()};\n\n            if (!User32.GetCursorInfo(ref cursorInfo))\n                return IntPtr.Zero;\n\n            if (cursorInfo.flags != CursorShowing)\n                return IntPtr.Zero;\n\n            var hIcon = User32.CopyIcon(cursorInfo.hCursor);\n\n            if (hIcon == IntPtr.Zero)\n                return IntPtr.Zero;\n\n            if (!User32.GetIconInfo(hIcon, out var icInfo))\n                return IntPtr.Zero;\n\n            var hotspot = new Point(icInfo.xHotspot, icInfo.yHotspot);\n\n            Location = new Point(cursorInfo.ptScreenPos.X - hotspot.X,\n                cursorInfo.ptScreenPos.Y - hotspot.Y);\n\n            if (Transform != null)\n                Location = Transform(Location);\n\n            Gdi32.DeleteObject(icInfo.hbmColor);\n            Gdi32.DeleteObject(icInfo.hbmMask);\n\n            return hIcon;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Capture/RegionProvider.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Native;\nusing Captura.Windows;\nusing Captura.Windows.Gdi;\n\nnamespace Captura.Video\n{\n    class RegionProvider : IImageProvider\n    {\n        Rectangle _region;\n        readonly Func<Point> _locationFunc;\n        readonly bool _includeCursor;\n\n        readonly IntPtr _hdcSrc;\n        readonly ITargetDeviceContext _dcTarget;\n\n        public RegionProvider(Rectangle Region,\n            IPreviewWindow PreviewWindow,\n            bool IncludeCursor,\n            Func<Point> LocationFunc = null)\n        {\n            _region = Region;\n            _includeCursor = IncludeCursor;\n            _locationFunc = LocationFunc ?? (() => Region.Location);\n\n            // Width and Height must be even.\n            // Use these for Bitmap size, but capture as per region size\n            Width = _region.Width;\n            if (Width % 2 == 1)\n                ++Width;\n            \n            Height = _region.Height;\n            if (Height % 2 == 1)\n                ++Height;\n\n            PointTransform = P => new Point(P.X - _region.X, P.Y - _region.Y);\n\n            _hdcSrc = User32.GetDC(IntPtr.Zero);\n\n            if (WindowsModule.ShouldUseGdi)\n            {\n                _dcTarget = new GdiTargetDeviceContext(_hdcSrc, Width, Height);\n            }\n            else _dcTarget = new DxgiTargetDeviceContext(PreviewWindow, Width, Height);\n        }\n\n        public void Dispose()\n        {\n            _dcTarget.Dispose();\n\n            User32.ReleaseDC(IntPtr.Zero, _hdcSrc);            \n        }\n\n        public IEditableFrame Capture()\n        {\n            // Update Location\n            _region.Location = _locationFunc();\n\n            var hdcDest = _dcTarget.GetDC();\n\n            Gdi32.BitBlt(hdcDest, 0, 0, _region.Width, _region.Height,\n                _hdcSrc, _region.X, _region.Y,\n                (int) CopyPixelOperation.SourceCopy);\n\n            if (_includeCursor)\n                MouseCursor.Draw(hdcDest, PointTransform);\n\n            var img = _dcTarget.GetEditableFrame();\n\n            return img;\n        }\n\n        public Func<Point, Point> PointTransform { get; }\n\n        public int Height { get; }\n        public int Width { get; }\n\n        public IBitmapFrame DummyFrame => _dcTarget.DummyFrame;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Capture/ScreenShot.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Windows.Gdi;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Contains methods for taking ScreenShots\n    /// </summary>\n    static class ScreenShot\n    {\n        /// <summary>\n        /// Capture transparent Screenshot of a Window.\n        /// </summary>\n        public static IBitmapImage CaptureTransparent(IWindow Window, bool IncludeCursor, IPlatformServices PlatformServices)\n        {\n            if (Window == null)\n                throw new ArgumentNullException(nameof(Window));\n\n            var backdrop = new WindowScreenShotBackdrop(Window, PlatformServices);\n\n            backdrop.ShowWhite();\n\n            var r = backdrop.Rectangle;\n\n            // Capture screenshot with white background\n            using var whiteShot = CaptureInternal(r);\n            backdrop.ShowBlack();\n\n            // Capture screenshot with black background\n            using var blackShot = CaptureInternal(r);\n            backdrop.Dispose();\n\n            var transparentImage = GraphicsExtensions.DifferentiateAlpha(whiteShot, blackShot);\n\n            if (transparentImage == null)\n                return null;\n\n            // Include Cursor only if within window\n            if (IncludeCursor && r.Contains(PlatformServices.CursorPosition))\n            {\n                using var g = Graphics.FromImage(transparentImage);\n                MouseCursor.Draw(g, P => new Point(P.X - r.X, P.Y - r.Y));\n            }\n\n            return new DrawingImage(transparentImage.CropEmptyEdges());\n        }\n\n        static Bitmap CaptureInternal(Rectangle Region, bool IncludeCursor = false)\n        {\n            var bmp = new Bitmap(Region.Width, Region.Height);\n\n            using (var g = Graphics.FromImage(bmp))\n            {\n                g.CopyFromScreen(Region.Location, Point.Empty, Region.Size, CopyPixelOperation.SourceCopy);\n\n                if (IncludeCursor)\n                    MouseCursor.Draw(g, P => new Point(P.X - Region.X, P.Y - Region.Y));\n\n                g.Flush();\n            }\n\n            return bmp;\n        }\n\n        /// <summary>\n        /// Captures a Specific Region.\n        /// </summary>\n        /// <param name=\"Region\">A <see cref=\"Rectangle\"/> specifying the Region to Capture.</param>\n        /// <param name=\"IncludeCursor\">Whether to include the Mouse Cursor.</param>\n        /// <returns>The Captured Image.</returns>\n        public static IBitmapImage Capture(Rectangle Region, bool IncludeCursor = false)\n        {\n            return new DrawingImage(CaptureInternal(Region, IncludeCursor));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Capture/WindowProvider.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Native;\nusing Captura.Windows;\nusing Captura.Windows.Gdi;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Captures the specified window.\n    /// </summary>\n    class WindowProvider : IImageProvider\n    {\n        readonly IWindow _window;\n        readonly bool _includeCursor;\n\n        readonly IntPtr _hdcSrc;\n        readonly ITargetDeviceContext _dcTarget;\n\n        static Func<Point, Point> GetTransformer(IWindow Window)\n        {\n            var initialSize = Window.Rectangle.Even().Size;\n\n            return P =>\n            {\n                var rect = Window.Rectangle;\n                \n                var ratio = Math.Min((float)initialSize.Width / rect.Width, (float)initialSize.Height / rect.Height);\n\n                return new Point((int)((P.X - rect.X) * ratio), (int)((P.Y - rect.Y) * ratio));\n            };\n        }\n        \n        /// <summary>\n        /// Creates a new instance of <see cref=\"WindowProvider\"/>.\n        /// </summary>\n        public WindowProvider(IWindow Window, IPreviewWindow PreviewWindow, bool IncludeCursor)\n        {\n            _window = Window ?? throw new ArgumentNullException(nameof(Window));\n            _includeCursor = IncludeCursor;\n\n            var size = Window.Rectangle.Even().Size;\n            Width = size.Width;\n            Height = size.Height;\n\n            PointTransform = GetTransformer(Window);\n\n            _hdcSrc = User32.GetDC(IntPtr.Zero);\n\n            if (WindowsModule.ShouldUseGdi)\n            {\n                _dcTarget = new GdiTargetDeviceContext(_hdcSrc, Width, Height);\n            }\n            else _dcTarget = new DxgiTargetDeviceContext(PreviewWindow, Width, Height);\n        }\n\n        public Func<Point, Point> PointTransform { get; }\n\n        void OnCapture()\n        {\n            if (!_window.IsAlive)\n            {\n                throw new WindowClosedException();\n            }\n\n            var rect = _window.Rectangle.Even();\n            var ratio = Math.Min((float) Width / rect.Width, (float) Height / rect.Height);\n\n            var resizeWidth = (int) (rect.Width * ratio);\n            var resizeHeight = (int) (rect.Height * ratio);\n\n            var hdcDest = _dcTarget.GetDC();\n\n            void ClearRect(RECT Rect)\n            {\n                User32.FillRect(hdcDest, ref Rect, IntPtr.Zero);\n            }\n\n            if (Width != resizeWidth)\n            {\n                ClearRect(new RECT\n                {\n                    Left = resizeWidth,\n                    Right = Width,\n                    Bottom = Height\n                });\n            }\n            else if (Height != resizeHeight)\n            {\n                ClearRect(new RECT\n                {\n                    Top = resizeHeight,\n                    Right = Width,\n                    Bottom = Height\n                });\n            }\n\n            Gdi32.StretchBlt(hdcDest, 0, 0, resizeWidth, resizeHeight,\n                _hdcSrc, rect.X, rect.Y, rect.Width, rect.Height,\n                (int) CopyPixelOperation.SourceCopy);\n\n            if (_includeCursor)\n                MouseCursor.Draw(hdcDest, PointTransform);\n        }\n\n        public IEditableFrame Capture()\n        {\n            try\n            {\n                OnCapture();\n\n                var img = _dcTarget.GetEditableFrame();\n\n                return img;\n            }\n            catch (Exception e) when (!(e is WindowClosedException))\n            {\n                return RepeatFrame.Instance;\n            }\n        }\n\n        /// <summary>\n        /// Height of Captured image.\n        /// </summary>\n        public int Height { get; }\n\n        /// <summary>\n        /// Width of Captured image.\n        /// </summary>\n        public int Width { get; }\n\n        public void Dispose()\n        {\n            _dcTarget.Dispose();\n\n            User32.ReleaseDC(IntPtr.Zero, _hdcSrc);\n        }\n\n        public IBitmapFrame DummyFrame => _dcTarget.DummyFrame;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Capture/WindowScreenShotBackdrop.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Windows.Forms;\nusing Captura.Native;\n\nnamespace Captura.Video\n{\n    class WindowScreenShotBackdrop : IDisposable\n    {\n        readonly IWindow _window;\n        readonly Form _form;\n\n        bool _shown;\n\n        public Rectangle Rectangle { get; }\n\n        public WindowScreenShotBackdrop(IWindow Window, IPlatformServices PlatformServices)\n        {\n            _window = Window;\n\n            // Show and Focus\n            User32.ShowWindow(Window.Handle, 5);\n\n            _form = new Form\n            {\n                AllowTransparency = true,\n                BackColor = Color.White,\n                FormBorderStyle = FormBorderStyle.None,\n                ShowInTaskbar = false\n            };\n\n            var r = Window.Rectangle;\n\n            // Add a margin for window shadows. Excess transparency is trimmed out later\n            r.Inflate(20, 20);\n\n            // Check if the window is outside of the visible screen\n            r.Intersect(PlatformServices.DesktopRectangle);\n\n            Rectangle = r;\n        }\n\n        void Show()\n        {\n            if (_shown)\n                return;\n\n            _shown = true;\n\n            _form.Show();\n\n            User32.SetWindowPos(_form.Handle, _window.Handle,\n                Rectangle.Left, Rectangle.Top,\n                Rectangle.Width, Rectangle.Height,\n                SetWindowPositionFlags.NoActivate);\n        }\n\n        public void ShowWhite()\n        {\n            Show();\n\n            _form.BackColor = Color.White;\n\n            // Wait for Backdrop to update\n            Application.DoEvents();\n        }\n\n        public void ShowBlack()\n        {\n            Show();\n\n            _form.BackColor = Color.Black;\n\n            // Wait for Backdrop to update\n            Application.DoEvents();\n        }\n\n        public void Dispose()\n        {\n            _form.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/ClipboardService.cs",
    "content": "﻿using System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Windows.Forms;\nusing Captura.Models;\nusing Captura.Windows.Gdi;\n\nnamespace Captura.Windows\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class ClipboardService : IClipboardService\n    {\n        readonly IMessageProvider _messageProvider;\n\n        public ClipboardService(IMessageProvider MessageProvider)\n        {\n            _messageProvider = MessageProvider;\n        }\n\n        public void SetText(string Text)\n        {\n            if (Text == null)\n                return;\n\n            try { Clipboard.SetText(Text); }\n            catch (ExternalException)\n            {\n                _messageProvider?.ShowError($\"Copy to Clipboard failed:\\n\\n{Text}\");\n            }\n        }\n\n        public string GetText() => Clipboard.GetText();\n\n        public bool HasText => Clipboard.ContainsText();\n\n        public void SetImage(IBitmapImage Bmp)\n        {\n            using var pngStream = new MemoryStream();\n            Bmp.Save(pngStream, ImageFormats.Png);\n            var pngClipboardData = new DataObject(\"PNG\", pngStream);\n\n            using var whiteS = new Bitmap(Bmp.Width, Bmp.Height, PixelFormat.Format24bppRgb);\n            Image drawingImg;\n\n            if (Bmp is DrawingImage drawingImage)\n                drawingImg = drawingImage.Image;\n            else drawingImg = Image.FromStream(pngStream);\n\n            using (var graphics = Graphics.FromImage(whiteS))\n            {\n                graphics.Clear(Color.White);\n                graphics.DrawImage(drawingImg, 0, 0, Bmp.Width, Bmp.Height);\n            }\n\n            // Add fallback for applications that don't support PNG from clipboard (eg. Photoshop or Paint)\n            pngClipboardData.SetData(DataFormats.Bitmap, whiteS);\n\n            Clipboard.Clear();\n            Clipboard.SetDataObject(pngClipboardData, true);\n        }\n\n        public IBitmapImage GetImage() => new DrawingImage(Clipboard.GetImage());\n\n        public bool HasImage => Clipboard.ContainsImage();\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/AcquireResult.cs",
    "content": "﻿using SharpDX;\nusing SharpDX.DXGI;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public class AcquireResult\n    {\n        public AcquireResult(Result Result)\n        {\n            this.Result = Result;\n        }\n\n        public AcquireResult(Result Result, OutputDuplicateFrameInformation FrameInfo, Resource DesktopResource)\n        {\n            this.Result = Result;\n            this.FrameInfo = FrameInfo;\n            this.DesktopResource = DesktopResource;\n        }\n\n        public Result Result { get; }\n\n        public OutputDuplicateFrameInformation FrameInfo { get; }\n\n        public Resource DesktopResource { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/DeskDuplFullScreenImageProvider.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Video;\nusing Captura.Windows.DirectX;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    class DeskDuplFullScreenImageProvider : IImageProvider\n    {\n        readonly FullScreenDesktopDuplicator _dupl;\n\n        public DeskDuplFullScreenImageProvider(bool IncludeCursor,\n            IPreviewWindow PreviewWindow,\n            IPlatformServices PlatformServices)\n        {\n            _dupl = new FullScreenDesktopDuplicator(IncludeCursor, PreviewWindow, PlatformServices);\n        }\n\n        public int Height => _dupl.Height;\n\n        public int Width => _dupl.Width;\n\n        public Func<Point, Point> PointTransform => _dupl.PointTransform;\n        \n        public IEditableFrame Capture()\n        {\n            return _dupl.Capture();\n        }\n\n        public void Dispose()\n        {\n            _dupl?.Dispose();\n        }\n\n        public IBitmapFrame DummyFrame => Texture2DFrame.DummyFrame;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/DeskDuplImageProvider.cs",
    "content": "﻿using SharpDX.DXGI;\nusing System;\nusing System.Drawing;\nusing Captura.Video;\nusing Captura.Windows.DirectX;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    class DeskDuplImageProvider : IImageProvider\n    {\n        readonly DesktopDuplicator _dupl;\n\n        public DeskDuplImageProvider(Output1 Output, bool IncludeCursor, IPreviewWindow PreviewWindow)\n        {\n            var bounds = Output.Description.DesktopBounds;\n\n            Width = bounds.Right - bounds.Left;\n            Height = bounds.Bottom - bounds.Top;\n\n            PointTransform = P => new Point(P.X - bounds.Left, P.Y - bounds.Top);\n\n            _dupl = new DesktopDuplicator(IncludeCursor, Output, PreviewWindow);\n        }\n\n        public int Height { get; }\n\n        public int Width { get; }\n\n        public Func<Point, Point> PointTransform { get; }\n        \n        public IEditableFrame Capture()\n        {\n            return _dupl.Capture();\n        }\n\n        public void Dispose()\n        {\n            _dupl?.Dispose();\n        }\n\n        public IBitmapFrame DummyFrame => Texture2DFrame.DummyFrame;\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/DeskDuplOutputEntry.cs",
    "content": "﻿using SharpDX;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    class DeskDuplOutputEntry\n    {\n        public Point Location { get; set; }\n\n        public DuplCapture DuplCapture { get; set; }\n\n        public DxMousePointer MousePointer { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/DesktopDuplicator.cs",
    "content": "﻿// Adapted from https://github.com/jasonpang/desktop-duplication-net\n\nusing SharpDX.DXGI;\nusing System;\nusing Captura.Video;\nusing Captura.Windows.DirectX;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public class DesktopDuplicator : IDisposable\n    {\n        Direct2DEditorSession _editorSession;\n        DxMousePointer _mousePointer;\n        DuplCapture _duplCapture;\n\n        public DesktopDuplicator(bool IncludeCursor, Output1 Output, IPreviewWindow PreviewWindow)\n        {\n            _duplCapture = new DuplCapture(Output);\n\n            var bounds = Output.Description.DesktopBounds;\n            var width = bounds.Right - bounds.Left;\n            var height = bounds.Bottom - bounds.Top;\n            \n            _editorSession = new Direct2DEditorSession(width, height, PreviewWindow);\n\n            if (IncludeCursor)\n                _mousePointer = new DxMousePointer(_editorSession);\n        }\n        \n        public IEditableFrame Capture()\n        {\n            try\n            {\n                if (!_duplCapture.Get(_editorSession.DesktopTexture, _mousePointer))\n                    return RepeatFrame.Instance;\n            }\n            catch\n            {\n                try { _duplCapture.Init(); }\n                catch\n                {\n                    // ignored\n                }\n\n                return RepeatFrame.Instance;\n            }\n\n            var editor = new Direct2DEditor(_editorSession);\n\n            _mousePointer?.Draw(editor);\n\n            return editor;\n        }\n\n        public void Dispose()\n        {\n            try { _duplCapture.Dispose(); }\n            catch { }\n            finally { _duplCapture = null; }\n\n            // Mouse Pointer disposed later to prevent errors.\n            try { _mousePointer?.Dispose(); }\n            catch { }\n            finally { _mousePointer = null; }\n\n            try { _editorSession.Dispose(); }\n            catch { }\n            finally { _editorSession = null; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/DuplCapture.cs",
    "content": "﻿using System;\nusing SharpDX;\nusing SharpDX.Direct3D11;\nusing SharpDX.DXGI;\nusing Device = SharpDX.Direct3D11.Device;\nusing ResultCode = SharpDX.DXGI.ResultCode;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public class DuplCapture : IDisposable\n    {\n        readonly Output1 _output;\n        Device _device;\n        OutputDuplication _deskDupl;\n        FrameGrabber _frameGrabber;\n        Texture2D _bkpTexture;\n        readonly int _width, _height;\n\n        readonly object _syncLock = new object();\n\n        public DuplCapture(Output1 Output)\n        {\n            // Separate Device required otherwise AccessViolationException happens\n            using (var adapter = Output.GetParent<Adapter>())\n                _device = new Device(adapter);\n\n            _output = Output;\n\n            var bound = Output.Description.DesktopBounds;\n            _width = bound.Right - bound.Left;\n            _height = bound.Bottom - bound.Top;\n\n            Init();\n        }\n\n        public void Dispose()\n        {\n            lock (_syncLock)\n            {\n                _frameGrabber?.Dispose();\n\n                _deskDupl?.Dispose();\n\n                _bkpTexture?.Dispose();\n\n                _device.Dispose();\n                _device = null;\n            }\n        }\n\n        public void Init()\n        {\n            lock (_syncLock)\n            {\n                _frameGrabber?.Dispose();\n                _deskDupl?.Dispose();\n\n                try\n                {\n                    _deskDupl = _output.DuplicateOutput(_device);\n\n                    _frameGrabber = new FrameGrabber(_deskDupl);\n                }\n                catch (SharpDXException e) when (e.Descriptor == ResultCode.NotCurrentlyAvailable)\n                {\n                    throw new Exception(\n                        \"There is already the maximum number of applications using the Desktop Duplication API running, please close one of the applications and try again.\",\n                        e);\n                }\n                catch (SharpDXException e) when (e.Descriptor == ResultCode.Unsupported)\n                {\n                    throw new NotSupportedException(\n                        \"Desktop Duplication is not supported on this system.\\nIf you have multiple graphic cards, try running Captura on integrated graphics.\",\n                        e);\n                }\n            }\n        }\n\n        public bool Get(Texture2D Texture, DxMousePointer DxMousePointer, Point TargetPosition = default)\n        {\n            lock (_syncLock)\n            {\n                // Disposed\n                if (_device == null)\n                    return false;\n\n                if (_bkpTexture == null)\n                {\n                    var desc = Texture.Description;\n                    desc.Width = _width;\n                    desc.Height = _height;\n\n                    // _device is being used by Desktop Duplication\n                    _bkpTexture = new Texture2D(Texture.Device, desc);\n                }\n\n                var acquireResult = _frameGrabber.Grab();\n\n                if (acquireResult == null)\n                {\n                    // _device is being used by Desktop Duplication\n                    Texture.Device.ImmediateContext.CopySubresourceRegion(_bkpTexture,\n                        0,\n                        new ResourceRegion(0, 0, 0, _width, _height, 1),\n                        Texture,\n                        0,\n                        TargetPosition.X, TargetPosition.Y);\n\n                    return true;\n                }\n\n                if (acquireResult.Result.Failure)\n                {\n                    throw new Exception($\"Failed to acquire next frame: {acquireResult.Result.Code}\");\n                }\n\n                using (acquireResult.DesktopResource)\n                using (var tempTexture = acquireResult.DesktopResource.QueryInterface<Texture2D>())\n                {\n                    DxMousePointer?.Update(tempTexture, acquireResult.FrameInfo, _deskDupl);\n\n                    Texture.Device.ImmediateContext.CopySubresourceRegion(tempTexture,\n                        0,\n                        new ResourceRegion(0, 0, 0, _width, _height, 1),\n                        Texture,\n                        0,\n                        TargetPosition.X, TargetPosition.Y);\n\n                    _device.ImmediateContext.CopyResource(tempTexture, _bkpTexture);\n                }\n\n                _frameGrabber.Release();\n\n                return true;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/FrameGrabber.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing SharpDX;\nusing SharpDX.DXGI;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public class FrameGrabber : IDisposable\n    {\n        readonly OutputDuplication _deskDupl;\n\n        AcquireResult _acquireResult;\n        readonly object _acquireResultLock = new object(),\n            _acquireTaskLock = new object();\n\n        Task _acquireTask;\n\n        public FrameGrabber(OutputDuplication DeskDupl)\n        {\n            _deskDupl = DeskDupl;\n        }\n\n        void BeginAcquireFrame()\n        {\n            const int timeout = 50;\n\n            _acquireTask = Task.Run(() =>\n            {\n                try\n                {\n                    var result = _deskDupl.TryAcquireNextFrame(timeout, out var frameInfo, out var desktopResource);\n\n                    if (result == ResultCode.WaitTimeout)\n                    {\n                        lock (_acquireResultLock)\n                        {\n                            _acquireResult = null;\n                        }\n\n                        BeginAcquireFrame();\n                    }\n                    else\n                    {\n                        lock (_acquireResultLock)\n                        {\n                            _acquireResult = new AcquireResult(result, frameInfo, desktopResource);\n                        }\n                    }\n                }\n                catch\n                {\n                    lock (_acquireResultLock)\n                    {\n                        _acquireResult = new AcquireResult(Result.Fail);\n                    }\n                }\n            });\n        }\n\n        AcquireResult GetAcquireResult()\n        {\n            lock (_acquireTaskLock)\n            {\n                if (_acquireTask == null)\n                {\n                    BeginAcquireFrame();\n\n                    return null;\n                }\n\n                _acquireTask.Wait();\n            }\n\n            lock (_acquireResultLock)\n            {\n                var val = _acquireResult;\n\n                _acquireResult = null;\n\n                return val;\n            }\n        }\n\n        public AcquireResult Grab()\n        {\n            return GetAcquireResult();\n        }\n\n        public void Release()\n        {\n            lock (_acquireTaskLock)\n            {\n                _deskDupl.ReleaseFrame();\n\n                BeginAcquireFrame();\n            }\n        }\n\n        public void Dispose()\n        {\n            lock (_acquireTaskLock)\n            {\n                try\n                {\n                    _acquireTask?.Wait();\n                }\n                catch { }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/FullScreenDesktopDuplicator.cs",
    "content": "﻿// Adapted from https://github.com/jasonpang/desktop-duplication-net\n\nusing SharpDX.DXGI;\nusing System;\nusing System.Drawing;\nusing System.Linq;\nusing System.Collections.Generic;\nusing Captura.Video;\nusing Captura.Windows.DirectX;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public class FullScreenDesktopDuplicator : IDisposable\n    {\n        Direct2DEditorSession _editorSession;\n        readonly List<DeskDuplOutputEntry> _outputs = new List<DeskDuplOutputEntry>();\n\n        public FullScreenDesktopDuplicator(bool IncludeCursor,\n            IPreviewWindow PreviewWindow,\n            IPlatformServices PlatformServices)\n        {\n            using var factory = new Factory1();\n            var outputs = factory\n                .Adapters1\n                .SelectMany(M => M.Outputs)\n                .ToArray();\n\n            var bounds = PlatformServices.DesktopRectangle;\n\n            Width = bounds.Width;\n            Height = bounds.Height;\n\n            PointTransform = P => new Point(P.X - bounds.Left, P.Y - bounds.Top);\n\n            _editorSession = new Direct2DEditorSession(Width, Height, PreviewWindow);\n\n            _outputs.AddRange(outputs.Select(M =>\n            {\n                var output1 = M.QueryInterface<Output1>();\n\n                var rect = M.Description.DesktopBounds;\n\n                return new DeskDuplOutputEntry\n                {\n                    DuplCapture = new DuplCapture(output1),\n                    Location = new SharpDX.Point(rect.Left - bounds.Left, rect.Top - bounds.Top),\n                    MousePointer = IncludeCursor ? new DxMousePointer(_editorSession) : null\n                };\n            }));\n        }\n\n        public int Width { get; }\n        public int Height { get; }\n\n        public Func<Point, Point> PointTransform { get; }\n\n        public IEditableFrame Capture()\n        {\n            foreach (var entry in _outputs)\n            {\n                try\n                {\n                    if (!entry.DuplCapture.Get(_editorSession.DesktopTexture, entry.MousePointer, entry.Location))\n                        return RepeatFrame.Instance;\n                }\n                catch\n                {\n                    try { entry.DuplCapture.Init(); }\n                    catch\n                    {\n                        // ignored\n                    }\n\n                    return RepeatFrame.Instance;\n                }                \n            }\n\n            var editor = new Direct2DEditor(_editorSession);\n\n            foreach (var entry in _outputs)\n            {\n                entry.MousePointer?.Draw(editor, entry.Location);\n            }\n\n            return editor;\n        }\n\n        public void Dispose()\n        {\n            foreach (var entry in _outputs)\n            {\n                try { entry.DuplCapture.Dispose(); }\n                catch { }\n                finally { entry.DuplCapture = null; }\n\n                // Mouse Pointer disposed later to prevent errors.\n                try { entry.MousePointer?.Dispose(); }\n                catch { }\n                finally { entry.MousePointer = null; }\n            }\n\n            try { _editorSession.Dispose(); }\n            catch { }\n            finally { _editorSession = null; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/MousePointer/ColorPointerShape.cs",
    "content": "﻿using System;\nusing SharpDX;\nusing SharpDX.Direct2D1;\nusing SharpDX.Direct3D11;\nusing SharpDX.DXGI;\nusing AlphaMode = SharpDX.Direct2D1.AlphaMode;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public class ColorPointerShape : IPointerShape\n    {\n        Bitmap _bmp;\n\n        public ColorPointerShape(IntPtr ShapeBuffer,\n            OutputDuplicatePointerShapeInformation ShapeInfo,\n            RenderTarget RenderTarget)\n        {\n            _bmp = new Bitmap(RenderTarget,\n                new Size2(ShapeInfo.Width, ShapeInfo.Height),\n                new DataPointer(ShapeBuffer, ShapeInfo.Height * ShapeInfo.Pitch),\n                ShapeInfo.Pitch,\n                new BitmapProperties(new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied)));\n        }\n\n        public void Update(Texture2D DesktopTexture, OutputDuplicatePointerPosition PointerPosition) { }\n\n        public Bitmap GetBitmap() => _bmp;\n\n        public void Dispose()\n        {\n            _bmp.Dispose();\n            _bmp = null;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/MousePointer/DXMousePointer.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\nusing Captura.Windows.DirectX;\nusing SharpDX;\nusing SharpDX.Direct3D11;\nusing SharpDX.DXGI;\nusing Rectangle = System.Drawing.Rectangle;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public class DxMousePointer : IDisposable\n    {\n        readonly Direct2DEditorSession _editorSession;\n\n        IntPtr _ptrShapeBuffer;\n        int _ptrShapeBufferSize;\n        OutputDuplicatePointerShapeInformation _ptrShapeInfo;\n        OutputDuplicatePointerPosition _pointerPosition;\n        IPointerShape _pointerShape;\n\n        const int PtrShapeMonochrome = 1;\n        const int PtrShapeColor = 2;\n        const int PtrShapeMaskedColor = 4;\n\n        public DxMousePointer(Direct2DEditorSession EditorSession)\n        {\n            _editorSession = EditorSession;\n        }\n\n        public void Update(Texture2D DesktopTexture, OutputDuplicateFrameInformation FrameInfo, OutputDuplication DeskDupl)\n        {\n            // No update\n            if (FrameInfo.LastMouseUpdateTime == 0)\n            {\n                _pointerShape?.Update(DesktopTexture, _pointerPosition);\n                return;\n            }\n\n            _pointerPosition = FrameInfo.PointerPosition;\n\n            if (FrameInfo.PointerShapeBufferSize != 0)\n            {\n                if (FrameInfo.PointerShapeBufferSize > _ptrShapeBufferSize)\n                {\n                    _ptrShapeBufferSize = FrameInfo.PointerShapeBufferSize;\n\n                    _ptrShapeBuffer = _ptrShapeBuffer != IntPtr.Zero\n                        ? Marshal.ReAllocCoTaskMem(_ptrShapeBuffer, _ptrShapeBufferSize)\n                        : Marshal.AllocCoTaskMem(_ptrShapeBufferSize);\n                }\n\n                DeskDupl.GetFramePointerShape(_ptrShapeBufferSize,\n                    _ptrShapeBuffer,\n                    out _,\n                    out _ptrShapeInfo);\n\n                _pointerShape?.Dispose();\n\n                switch (_ptrShapeInfo.Type)\n                {\n                    case PtrShapeMonochrome:\n                        _pointerShape = new MonochromePointerShape(_ptrShapeBuffer,\n                            _ptrShapeInfo,\n                            _editorSession);\n                        break;\n\n                    case PtrShapeMaskedColor:\n                        _pointerShape = new MaskedColorPointerShape(_ptrShapeBuffer,\n                            _ptrShapeInfo,\n                            _editorSession);\n                        break;\n\n                    case PtrShapeColor:\n                        _pointerShape = new ColorPointerShape(_ptrShapeBuffer,\n                            _ptrShapeInfo,\n                            _editorSession.RenderTarget);\n                        break;\n                }\n            }\n\n            _pointerShape?.Update(DesktopTexture, _pointerPosition);\n        }\n\n        public void Draw(Direct2DEditor Editor, Point Location = default)\n        {\n            if (!_pointerPosition.Visible)\n                return;\n\n            var bmp = _pointerShape?.GetBitmap();\n\n            if (bmp == null)\n                return;\n\n            var rect = new Rectangle(_pointerPosition.Position.X + Location.X,\n                _pointerPosition.Position.Y + Location.Y,\n                (int) bmp.Size.Width,\n                (int) bmp.Size.Height);\n\n            Editor.DrawImage(new Direct2DImage(bmp), rect);\n        }\n\n        public void Dispose()\n        {\n            if (_ptrShapeBuffer == IntPtr.Zero)\n                return;\n\n            _pointerShape?.Dispose();\n            Marshal.FreeCoTaskMem(_ptrShapeBuffer);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/MousePointer/IPointerShape.cs",
    "content": "﻿using System;\nusing SharpDX.Direct2D1;\nusing SharpDX.Direct3D11;\nusing SharpDX.DXGI;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public interface IPointerShape : IDisposable\n    {\n        void Update(Texture2D DesktopTexture, OutputDuplicatePointerPosition PointerPosition);\n\n        Bitmap GetBitmap();\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/MousePointer/MaskedColorPointerShape.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\nusing Captura.Windows.DirectX;\nusing SharpDX.DXGI;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public class MaskedColorPointerShape : MaskedPointerShape\n    {\n        byte[] _maskedShapeBuffer;\n\n        public MaskedColorPointerShape(IntPtr ShapeBuffer,\n            OutputDuplicatePointerShapeInformation ShapeInfo,\n            Direct2DEditorSession EditorSession)\n            : base(ShapeInfo.Width, ShapeInfo.Height, EditorSession)\n        {\n            _maskedShapeBuffer = new byte[Width * Height * 4];\n            Marshal.Copy(ShapeBuffer, _maskedShapeBuffer, 0, _maskedShapeBuffer.Length);\n        }\n\n        protected override void OnUpdate()\n        {\n            for (var row = 0; row < Height; ++row)\n            {\n                for (var col = 0; col < Width; ++col)\n                {\n                    var index = row * Width * 4 + col * 4;\n\n                    var mask = _maskedShapeBuffer[index + 3]; // Alpha value is mask\n\n                    if (mask != 0) // 0xFF\n                    {\n                        // XOR with screen pixels\n                        for (var i = 0; i < 3; ++i)\n                        {\n                            ShapeBuffer[index + i] = (byte)(DesktopBuffer[index + i] ^ _maskedShapeBuffer[index + i]);\n                        }\n                    }\n                    else\n                    {\n                        // Replace screen pixels\n                        for (var i = 0; i < 3; ++i)\n                        {\n                            ShapeBuffer[index + i] = _maskedShapeBuffer[index + i];\n                        }\n                    }\n\n                    // Alpha\n                    ShapeBuffer[index + 3] = 0xFF;\n                }\n            }\n        }\n\n        protected override void OnDispose()\n        {\n            _maskedShapeBuffer = null;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/MousePointer/MaskedPointerShape.cs",
    "content": "﻿using System.Runtime.InteropServices;\nusing Captura.Windows.DirectX;\nusing SharpDX;\nusing SharpDX.Direct2D1;\nusing SharpDX.Direct3D11;\nusing SharpDX.DXGI;\nusing AlphaMode = SharpDX.Direct2D1.AlphaMode;\nusing MapFlags = SharpDX.Direct3D11.MapFlags;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public abstract class MaskedPointerShape : IPointerShape\n    {\n        Direct2DEditorSession _editorSession;\n        Texture2D _copyTex;\n        Bitmap _bmp;\n        protected byte[] ShapeBuffer, DesktopBuffer;\n\n        protected int Width { get; }\n        protected int Height { get; }\n\n        public MaskedPointerShape(int Width, int Height, Direct2DEditorSession EditorSession)\n        {\n            this.Width = Width;\n            this.Height = Height;\n            _editorSession = EditorSession;\n\n            var copyTexDesc = new Texture2DDescription\n            {\n                Width = this.Width,\n                Height = this.Height,\n                MipLevels = 1,\n                ArraySize = 1,\n                Format = Format.B8G8R8A8_UNorm,\n                SampleDescription =\n                {\n                    Count = 1,\n                    Quality = 0\n                },\n                Usage = ResourceUsage.Staging,\n                BindFlags = 0,\n                CpuAccessFlags = CpuAccessFlags.Read\n            };\n\n            _copyTex = new Texture2D(_editorSession.Device, copyTexDesc);\n\n            ShapeBuffer = new byte[Width * Height * 4];\n            DesktopBuffer = new byte[Width * Height * 4];\n        }\n\n        public Bitmap GetBitmap() => _bmp;\n\n        public void Update(Texture2D DesktopTexture, OutputDuplicatePointerPosition PointerPosition)\n        {\n            _bmp?.Dispose();\n\n            var region = new ResourceRegion(\n                PointerPosition.Position.X,\n                PointerPosition.Position.Y,\n                0,\n                PointerPosition.Position.X + Width,\n                PointerPosition.Position.Y + Height,\n                1);\n\n            _editorSession.Device.ImmediateContext.CopySubresourceRegion(\n                DesktopTexture,\n                0,\n                region,\n                _copyTex,\n                0);\n\n            var desktopMap = _editorSession.Device.ImmediateContext.MapSubresource(\n                _copyTex,\n                0,\n                MapMode.Read,\n                MapFlags.None);\n\n            try\n            {\n                Marshal.Copy(desktopMap.DataPointer, DesktopBuffer, 0, DesktopBuffer.Length);\n            }\n            finally\n            {\n                _editorSession.Device.ImmediateContext.UnmapSubresource(_copyTex, 0);\n            }\n\n            OnUpdate();\n\n            var gcPin = GCHandle.Alloc(ShapeBuffer, GCHandleType.Pinned);\n\n            try\n            {\n                var pitch = Width * 4;\n\n                _bmp = new Bitmap(_editorSession.RenderTarget,\n                    new Size2(Width, Height),\n                    new DataPointer(gcPin.AddrOfPinnedObject(), Height * pitch),\n                    pitch,\n                    new BitmapProperties(new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied)));\n            }\n            finally\n            {\n                gcPin.Free();\n            }\n        }\n\n        protected abstract void OnUpdate();\n        protected abstract void OnDispose();\n\n        public void Dispose()\n        {\n            _bmp?.Dispose();\n            _bmp = null;\n\n            _copyTex?.Dispose();\n            _copyTex = null;\n\n            ShapeBuffer = DesktopBuffer = null;\n\n            _editorSession = null;\n\n            OnDispose();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DesktopDuplication/MousePointer/MonochromePointerShape.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\nusing Captura.Windows.DirectX;\nusing SharpDX.DXGI;\n\nnamespace Captura.Windows.DesktopDuplication\n{\n    public class MonochromePointerShape : MaskedPointerShape\n    {\n        byte[] _andMaskBuffer, _xorMaskBuffer;\n\n        public MonochromePointerShape(IntPtr ShapeBuffer,\n            OutputDuplicatePointerShapeInformation ShapeInfo,\n            Direct2DEditorSession EditorSession)\n            : base(ShapeInfo.Width, ShapeInfo.Height / 2, EditorSession)\n        {\n            _andMaskBuffer = new byte[Width * Height / 8];\n            Marshal.Copy(ShapeBuffer, _andMaskBuffer, 0, _andMaskBuffer.Length);\n\n            _xorMaskBuffer = new byte[Width * Height / 8];\n            Marshal.Copy(ShapeBuffer + _andMaskBuffer.Length, _xorMaskBuffer, 0, _xorMaskBuffer.Length);\n        }\n\n        // BGRA\n        static readonly byte[] White = { 0xFF, 0xFF, 0xFF, 0xFF };\n        static readonly byte[] Black = { 0, 0, 0, 0xFF };\n        static readonly byte[] TransparentWhite = { 0xFF, 0xFF, 0xFF, 0 };\n        static readonly byte[] TransparentBlack = new byte[4];\n\n        protected override void OnUpdate()\n        {\n            for (var row = 0; row < Height; ++row)\n            {\n                byte bit = 0x80;\n\n                for (var col = 0; col < Width; ++col)\n                {\n                    var maskIndex = row * Width / 8 + col / 8;\n\n                    var andMask = (_andMaskBuffer[maskIndex] & bit) == bit;\n                    var xorMask = (_xorMaskBuffer[maskIndex] & bit) == bit;\n\n                    var andMask32 = andMask ? White : Black;\n                    var xorMask32 = xorMask ? TransparentWhite : TransparentBlack;\n\n                    var index = row * Width * 4 + col * 4;\n\n                    for (var k = 0; k < 4; ++k)\n                    {\n                        ShapeBuffer[index + k] = (byte)((DesktopBuffer[index + k] & andMask32[k]) ^ xorMask32[k]);\n                    }\n\n                    if (bit == 0x01)\n                    {\n                        bit = 0x80;\n                    }\n                    else bit = (byte)(bit >> 1);\n                }\n            }\n        }\n\n        protected override void OnDispose()\n        {\n            _andMaskBuffer = _xorMaskBuffer = null;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/DialogService.cs",
    "content": "﻿using System.Windows.Forms;\nusing Captura.Models;\nusing Ookii.Dialogs;\n\nnamespace Captura.Windows\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class DialogService : IDialogService\n    {\n        public string PickFolder(string Current, string Description)\n        {\n            using (var dlg = new VistaFolderBrowserDialog\n            {\n                SelectedPath = Current,\n                UseDescriptionForTitle = true,\n                Description = Description\n            })\n            {\n                if (dlg.ShowDialog() == DialogResult.OK)\n                    return dlg.SelectedPath;\n            }\n\n            return null;\n        }\n\n        public string PickFile(string InitialFolder, string Description)\n        {\n            var ofd = new OpenFileDialog\n            {\n                CheckFileExists = true,\n                CheckPathExists = true,\n                InitialDirectory = InitialFolder,\n                Title = Description\n            };\n\n            return ofd.ShowDialog() == DialogResult.OK ? ofd.FileName : null;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Direct2D/D3D9PreviewAssister.cs",
    "content": "﻿using System;\nusing SharpDX.Direct3D11;\nusing SharpDX.Direct3D9;\n\n// Adapted from https://github.com/Marlamin/SharpDX.WPF\n\nnamespace Captura.Windows.DirectX\n{\n    public class D3D9PreviewAssister : IDisposable\n    {\n        readonly Direct3DEx _direct3D;\n        readonly DeviceEx _device;\n\n        public D3D9PreviewAssister(IPlatformServices PlatformServices)\n        {\n            _direct3D = new Direct3DEx();\n\n            var presentparams = new PresentParameters\n            {\n                Windowed = true,\n                SwapEffect = SwapEffect.Discard,\n                DeviceWindowHandle = PlatformServices.DesktopWindow.Handle,\n                PresentationInterval = PresentInterval.Default\n            };\n\n            _device = new DeviceEx(_direct3D,\n                0,\n                DeviceType.Hardware,\n                IntPtr.Zero,\n                CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve,\n                presentparams);\n        }\n\n        public Texture GetSharedTexture(Texture2D Texture)\n        {\n            return GetSharedD3D9(_device, Texture);\n        }\n\n        // Texture must be created with ResourceOptionFlags.Shared\n        // Texture format must be B8G8R8A8_UNorm\n        static Texture GetSharedD3D9(DeviceEx Device, Texture2D RenderTarget)\n        {\n            using var resource = RenderTarget.QueryInterface<SharpDX.DXGI.Resource>();\n            var handle = resource.SharedHandle;\n\n            if (handle == IntPtr.Zero)\n                throw new ArgumentNullException(nameof(handle));\n\n            return new Texture(Device,\n                RenderTarget.Description.Width,\n                RenderTarget.Description.Height,\n                1,\n                Usage.RenderTarget,\n                Format.A8R8G8B8,\n                Pool.Default,\n                ref handle);\n        }\n\n        public void Dispose()\n        {\n            _device.Dispose();\n            _direct3D.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Direct2D/Direct2DEditor.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing SharpDX;\nusing SharpDX.Direct2D1;\nusing SharpDX.DirectWrite;\nusing SharpDX.DXGI;\nusing SharpDX.Mathematics.Interop;\nusing SharpDX.WIC;\nusing AlphaMode = SharpDX.Direct2D1.AlphaMode;\nusing Bitmap = SharpDX.Direct2D1.Bitmap;\nusing BitmapInterpolationMode = SharpDX.Direct2D1.BitmapInterpolationMode;\nusing Color = System.Drawing.Color;\nusing PixelFormat = SharpDX.WIC.PixelFormat;\nusing Point = System.Drawing.Point;\nusing RectangleF = System.Drawing.RectangleF;\n\nnamespace Captura.Windows.DirectX\n{\n    public class Direct2DEditor : IEditableFrame\n    {\n        readonly Direct2DEditorSession _editorSession;\n\n        public Direct2DEditor(Direct2DEditorSession EditorSession)\n        {\n            _editorSession = EditorSession;\n\n            var desc = EditorSession.StagingTexture.Description;\n\n            Width = desc.Width;\n            Height = desc.Height;\n\n            EditorSession.BeginDraw();\n        }\n\n        public void Dispose() { }\n\n        public float Width { get; }\n        public float Height { get; }\n\n        public IBitmapImage CreateBitmapBgr32(Size Size, IntPtr MemoryData, int Stride)\n        {\n            var bmp = new Bitmap(_editorSession.RenderTarget,\n                new Size2(Size.Width, Size.Height),\n                new DataPointer(MemoryData, Size.Height * Stride),\n                Stride,\n                new BitmapProperties(new SharpDX.Direct2D1.PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Ignore)));\n\n            return new Direct2DImage(bmp);\n        }\n\n        public IBitmapImage LoadBitmap(string FileName)\n        {\n            using var decoder = new BitmapDecoder(_editorSession.ImagingFactory, FileName, 0);\n            using var bmpSource = decoder.GetFrame(0);\n            using var convertedBmp = new FormatConverter(_editorSession.ImagingFactory);\n            convertedBmp.Initialize(bmpSource, PixelFormat.Format32bppPBGRA);\n\n            var bmp = Bitmap.FromWicBitmap(_editorSession.RenderTarget, convertedBmp);\n\n            return new Direct2DImage(bmp);\n        }\n\n        public void DrawImage(IBitmapImage Image, RectangleF? Region, int Opacity = 100)\n        {\n            if (Image is Direct2DImage direct2DImage)\n            {\n                var bmp = direct2DImage.Bitmap;\n\n                var rect = Region ?? new RectangleF(0, 0, bmp.Size.Width, bmp.Size.Height);\n                var rawRect = new RawRectangleF(rect.Left,\n                    rect.Top,\n                    rect.Right,\n                    rect.Bottom);\n\n                _editorSession.RenderTarget.DrawBitmap(bmp, rawRect, Opacity, BitmapInterpolationMode.Linear);\n            }\n        }\n\n        SolidColorBrush Convert(Color Color)\n        {\n            var color = new RawColor4(Color.R / 255f, Color.G / 255f, Color.B / 255f, Color.A / 255f);\n\n            return _editorSession.GetSolidColorBrush(color);\n        }\n\n        RawRectangleF Convert(RectangleF Rectangle)\n        {\n            return new RawRectangleF(Rectangle.Left,\n                Rectangle.Top,\n                Rectangle.Right,\n                Rectangle.Bottom);\n        }\n\n        RoundedRectangle Convert(RectangleF Rectangle, int CornerRadius)\n        {\n            return new RoundedRectangle\n            {\n                Rect = Convert(Rectangle),\n                RadiusX = CornerRadius,\n                RadiusY = CornerRadius\n            };\n        }\n\n        RawVector2 Convert(Point P)\n        {\n            return new RawVector2(P.X, P.Y);\n        }\n\n        Ellipse ToEllipse(RectangleF Rectangle)\n        {\n            var center = new RawVector2(Rectangle.Left + Rectangle.Width / 2f,\n                Rectangle.Top + Rectangle.Height / 2f);\n\n            return new Ellipse(center,\n                Rectangle.Width / 2f,\n                Rectangle.Height / 2f);\n        }\n\n        public void DrawLine(Point Start, Point End, Color Color, float Width)\n        {\n            _editorSession.RenderTarget.DrawLine(Convert(Start), Convert(End), Convert(Color), Width);\n        }\n\n        public void DrawArrow(Point Start, Point End, Color Color, float Width)\n        {\n            var props = new StrokeStyleProperties\n            {\n                EndCap = CapStyle.Round,\n                LineJoin = LineJoin.Round\n            };\n\n            var style = new StrokeStyle(_editorSession.RenderTarget.Factory, props);\n\n            _editorSession.RenderTarget.DrawLine(Convert(Start), Convert(End), Convert(Color), Width, style);\n\n            var direction = new Vector2(End.X - Start.X, End.Y - Start.Y);\n            var theta = Math.Atan2(direction.Y, direction.X);\n\n            const double rotateBy = 3 * Math.PI / 4;\n            var sideLen = Width * 2;\n\n            // Start drawing from ending point\n            Start = End;\n\n            var ltheta = theta - rotateBy;\n            End = new Point((int)(Start.X + sideLen * Math.Cos(ltheta)), (int)(Start.Y + sideLen * Math.Sin(ltheta)));\n            _editorSession.RenderTarget.DrawLine(Convert(Start), Convert(End), Convert(Color), Width, style);\n\n            var rtheta = theta + rotateBy;\n            End = new Point((int)(Start.X + sideLen * Math.Cos(rtheta)), (int)(Start.Y + sideLen * Math.Sin(rtheta)));\n            _editorSession.RenderTarget.DrawLine(Convert(Start), Convert(End), Convert(Color), Width, style);\n        }\n\n        public void FillRectangle(Color Color, RectangleF Rectangle)\n        {\n            _editorSession.RenderTarget.FillRectangle(Convert(Rectangle), Convert(Color));\n        }\n\n        public void FillRectangle(Color Color, RectangleF Rectangle, int CornerRadius)\n        {\n            _editorSession.RenderTarget.FillRoundedRectangle(Convert(Rectangle, CornerRadius), Convert(Color));\n        }\n\n        public void DrawRectangle(Color Color, float StrokeWidth, RectangleF Rectangle)\n        {\n            _editorSession.RenderTarget.DrawRectangle(Convert(Rectangle), Convert(Color), StrokeWidth);\n        }\n\n        public void DrawRectangle(Color Color, float StrokeWidth, RectangleF Rectangle, int CornerRadius)\n        {\n            _editorSession.RenderTarget.DrawRoundedRectangle(Convert(Rectangle, CornerRadius), Convert(Color), StrokeWidth);\n        }\n\n        public void FillEllipse(Color Color, RectangleF Rectangle)\n        {\n            _editorSession.RenderTarget.FillEllipse(ToEllipse(Rectangle), Convert(Color));\n        }\n\n        public void DrawEllipse(Color Color, float StrokeWidth, RectangleF Rectangle)\n        {\n            _editorSession.RenderTarget.DrawEllipse(ToEllipse(Rectangle), Convert(Color), StrokeWidth);\n        }\n\n        public IFont GetFont(string FontFamily, int Size)\n        {\n            return new Direct2DFont(FontFamily, Size, _editorSession.WriteFactory);\n        }\n\n        TextLayout GetTextLayout(string Text, TextFormat Format)\n        {\n            return new TextLayout(_editorSession.WriteFactory, Text, Format, Width, Height);\n        }\n\n        public SizeF MeasureString(string Text, IFont Font)\n        {\n            if (Font is Direct2DFont font)\n            {\n                using var layout = GetTextLayout(Text, font.TextFormat);\n                return new SizeF(layout.Metrics.Width, layout.Metrics.Height);\n            }\n\n            return SizeF.Empty;\n        }\n\n        public void DrawString(string Text, IFont Font, Color Color, RectangleF LayoutRectangle)\n        {\n            if (Font is Direct2DFont font)\n            {\n                using var layout = GetTextLayout(Text, font.TextFormat);\n                _editorSession.RenderTarget.DrawTextLayout(\n                    new RawVector2(LayoutRectangle.X, LayoutRectangle.Y),\n                    layout,\n                    Convert(Color));\n            }\n        }\n\n        public IBitmapFrame GenerateFrame(TimeSpan Timestamp)\n        {\n            _editorSession.EndDraw();\n\n            return new Texture2DFrame(_editorSession.StagingTexture,\n                _editorSession.Device,\n                _editorSession.PreviewTexture,\n                Timestamp,\n                _editorSession.ColorConverter);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Direct2D/Direct2DEditorSession.cs",
    "content": "﻿using System;\nusing Captura.Windows.MediaFoundation;\nusing Captura.Video;\nusing SharpDX.Direct2D1;\nusing SharpDX.Direct3D;\nusing SharpDX.Direct3D11;\nusing SharpDX.DXGI;\nusing SharpDX.Mathematics.Interop;\nusing SharpDX.WIC;\nusing AlphaMode = SharpDX.Direct2D1.AlphaMode;\nusing Device = SharpDX.Direct3D11.Device;\nusing Factory = SharpDX.DirectWrite.Factory;\nusing Factory1 = SharpDX.Direct2D1.Factory1;\nusing PixelFormat = SharpDX.Direct2D1.PixelFormat;\n\nnamespace Captura.Windows.DirectX\n{\n    public class Direct2DEditorSession : IDisposable\n    {\n        readonly IPreviewWindow _previewWindow;\n        public Texture2D DesktopTexture { get; private set; }\n\n        public Device Device { get; private set; }\n        public Texture2D StagingTexture { get; private set; }\n        public RenderTarget RenderTarget { get; private set; }\n        public Texture2D PreviewTexture { get; private set; }\n\n        SolidColorBrush _solidColorBrush;\n        Factory1 _factory;\n        Factory _writeFactory;\n        ImagingFactory _imagingFactory;\n\n        public Factory WriteFactory => _writeFactory ??= new Factory();\n\n        public ImagingFactory ImagingFactory => _imagingFactory ??= new ImagingFactory();\n\n        public Lazy<MfColorConverter> ColorConverter { get; }\n\n        public SolidColorBrush GetSolidColorBrush(RawColor4 Color)\n        {\n            if (_solidColorBrush == null)\n            {\n                _solidColorBrush = new SolidColorBrush(RenderTarget, Color);\n            }\n            else _solidColorBrush.Color = Color;\n\n            return _solidColorBrush;\n        }\n\n        public Direct2DEditorSession(int Width, int Height, IPreviewWindow PreviewWindow)\n        {\n            _previewWindow = PreviewWindow;\n\n            Device = new Device(DriverType.Hardware,\n                DeviceCreationFlags.BgraSupport | DeviceCreationFlags.VideoSupport);\n\n            StagingTexture = new Texture2D(Device, new Texture2DDescription\n            {\n                CpuAccessFlags = CpuAccessFlags.Read,\n                BindFlags = BindFlags.None,\n                Format = Format.B8G8R8A8_UNorm,\n                Width = Width,\n                Height = Height,\n                OptionFlags = ResourceOptionFlags.None,\n                MipLevels = 1,\n                ArraySize = 1,\n                SampleDescription = { Count = 1, Quality = 0 },\n                Usage = ResourceUsage.Staging\n            });\n\n            DesktopTexture = new Texture2D(Device, new Texture2DDescription\n            {\n                CpuAccessFlags = CpuAccessFlags.None,\n                BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,\n                Format = Format.B8G8R8A8_UNorm,\n                Width = Width,\n                Height = Height,\n                OptionFlags = ResourceOptionFlags.None,\n                MipLevels = 1,\n                ArraySize = 1,\n                SampleDescription = { Count = 1, Quality = 0 },\n                Usage = ResourceUsage.Default\n            });\n\n            var desc = DesktopTexture.Description;\n            desc.OptionFlags = ResourceOptionFlags.Shared;\n\n            PreviewTexture = new Texture2D(Device, desc);\n\n            _factory = new Factory1(FactoryType.MultiThreaded);\n\n            var pixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Ignore);\n\n            var renderTargetProps = new RenderTargetProperties(pixelFormat);\n\n            using (var surface = DesktopTexture.QueryInterface<Surface>())\n            {\n                RenderTarget = new RenderTarget(_factory, surface, renderTargetProps);\n            }\n\n            ColorConverter = new Lazy<MfColorConverter>(() => new MfColorConverter(Width, Height, Device));\n        }\n\n        public Texture2D CreateGdiTexture(int Width, int Height)\n        {\n            var desc = new Texture2DDescription\n            {\n                Width = Width,\n                Height = Height,\n                ArraySize = 1,\n                Format = Format.B8G8R8A8_UNorm,\n                Usage = ResourceUsage.Default,\n                BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,\n                MipLevels = 1,\n                SampleDescription = { Count = 1 },\n                OptionFlags = ResourceOptionFlags.GdiCompatible\n            };\n\n            return new Texture2D(Device, desc);\n        }\n\n        public void BeginDraw()\n        {\n            RenderTarget.BeginDraw();\n        }\n\n        public void EndDraw()\n        {\n            RenderTarget.EndDraw();\n            Device.ImmediateContext.CopyResource(DesktopTexture, StagingTexture);\n\n            if (_previewWindow.IsVisible)\n            {\n                Device.ImmediateContext.CopyResource(StagingTexture, PreviewTexture);\n            }\n\n            // Actual CopyResource happens here\n            Device.ImmediateContext.Flush();\n        }\n\n        public void Dispose()\n        {\n            if (ColorConverter.IsValueCreated)\n            {\n                ColorConverter.Value.Dispose();\n            }\n\n            _solidColorBrush?.Dispose();\n            _solidColorBrush = null;\n\n            RenderTarget.Dispose();\n            RenderTarget = null;\n\n            _factory.Dispose();\n            _factory = null;\n\n            _writeFactory?.Dispose();\n            _writeFactory = null;\n\n            _imagingFactory?.Dispose();\n            _imagingFactory = null;\n\n            PreviewTexture.Dispose();\n            PreviewTexture = null;\n\n            DesktopTexture.Dispose();\n            DesktopTexture = null;\n\n            StagingTexture.Dispose();\n            StagingTexture = null;\n\n            Device.Dispose();\n            Device = null;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Direct2D/Direct2DFont.cs",
    "content": "﻿using SharpDX.DirectWrite;\n\nnamespace Captura.Windows.DirectX\n{\n    public class Direct2DFont : IFont\n    {\n        public Direct2DFont(string FontFamily, int Size, Factory DirectWriteFactory)\n        {\n            this.FontFamily = FontFamily;\n            this.Size = Size;\n\n            try\n            {\n                TextFormat = new TextFormat(DirectWriteFactory, FontFamily, Size);\n            }\n            catch\n            {\n                TextFormat = new TextFormat(DirectWriteFactory, \"Arial\", Size);\n            }\n        }\n\n        public TextFormat TextFormat { get; }\n\n        public void Dispose()\n        {\n            TextFormat.Dispose();\n        }\n\n        public int Size { get; }\n        public string FontFamily { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Direct2D/Direct2DImage.cs",
    "content": "﻿using System.IO;\nusing SharpDX.Direct2D1;\n\nnamespace Captura.Windows.DirectX\n{\n    public class Direct2DImage : IBitmapImage\n    {\n        public Bitmap Bitmap { get; }\n\n        public Direct2DImage(Bitmap Bitmap)\n        {\n            this.Bitmap = Bitmap;\n\n            var size = Bitmap.PixelSize;\n\n            Width = size.Width;\n            Height = size.Height;\n        }\n\n        public void Dispose()\n        {\n            Bitmap.Dispose();\n        }\n\n        public int Width { get; }\n        public int Height { get; }\n\n        public void Save(string FileName, ImageFormats Format)\n        {\n            throw new System.NotImplementedException();\n        }\n\n        public void Save(Stream Stream, ImageFormats Format)\n        {\n            throw new System.NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Direct2D/Texture2DFrame.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\nusing System.Threading.Tasks;\nusing Captura.Windows.MediaFoundation;\nusing Captura.Native;\nusing SharpDX.Direct3D11;\nusing Device = SharpDX.Direct3D11.Device;\nusing MapFlags = SharpDX.Direct3D11.MapFlags;\n\nnamespace Captura.Windows.DirectX\n{\n    public class Texture2DFrame : INV12Frame\n    {\n        public Texture2D Texture { get; }\n        public Texture2D PreviewTexture { get; }\n\n        public Device Device { get; }\n\n        public TimeSpan Timestamp { get; }\n\n        readonly Lazy<MfColorConverter> _colorConverter;\n\n        public Texture2DFrame(Texture2D Texture,\n            Device Device,\n            Texture2D PreviewTexture,\n            TimeSpan Timestamp,\n            Lazy<MfColorConverter> ColorConverter)\n        {\n            _colorConverter = ColorConverter;\n            this.Timestamp = Timestamp;\n            this.Texture = Texture;\n            this.Device = Device;\n            this.PreviewTexture = PreviewTexture;\n\n            var desc = Texture.Description;\n\n            Width = desc.Width;\n            Height = desc.Height;\n        }\n\n        Texture2DFrame() { }\n\n        public static IBitmapFrame DummyFrame { get; } = new Texture2DFrame();\n\n        public void Dispose() { }\n\n        public int Width { get; }\n        public int Height { get; }\n\n        public void CopyTo(byte[] Buffer)\n        {\n            var mapSource = Device.ImmediateContext.MapSubresource(Texture, 0, MapMode.Read, MapFlags.None);\n\n            var destStride = Width * 4;\n\n            try\n            {\n                // Do not copy directly, strides may be different\n                Parallel.For(0, Height, Y =>\n                {\n                    Marshal.Copy(mapSource.DataPointer + Y * mapSource.RowPitch,\n                        Buffer,\n                        Y * destStride,\n                        destStride);\n                });\n            }\n            finally\n            {\n                Device.ImmediateContext.UnmapSubresource(Texture, 0);\n            }\n        }\n\n        public void CopyTo(IntPtr Buffer)\n        {\n            var mapSource = Device.ImmediateContext.MapSubresource(Texture, 0, MapMode.Read, MapFlags.None);\n\n            var destStride = Width * 4;\n\n            try\n            {\n                // Do not copy directly, strides may be different\n                Parallel.For(0, Height, Y =>\n                {\n                    Kernel32.CopyMemory(Buffer + Y * destStride,\n                        mapSource.DataPointer + Y * mapSource.RowPitch,\n                        destStride);\n                });\n            }\n            finally\n            {\n                Device.ImmediateContext.UnmapSubresource(Texture, 0);\n            }\n        }\n\n        public void CopyNV12To(byte[] Buffer)\n        {\n            _colorConverter.Value.Convert(Texture, Buffer);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Drawing/DrawingFont.cs",
    "content": "﻿using System.Drawing;\n\nnamespace Captura.Windows.Gdi\n{\n    public class DrawingFont : IFont\n    {\n        public DrawingFont(string FontFamily, int Size)\n        {\n            this.FontFamily = FontFamily;\n            this.Size = Size;\n\n            try\n            {\n                Font = new Font(new FontFamily(FontFamily), Size, GraphicsUnit.Pixel);\n            }\n            catch\n            {\n                Font = new Font(System.Drawing.FontFamily.GenericMonospace, Size, GraphicsUnit.Pixel);\n            }\n        }\n\n        public Font Font { get; }\n\n        public void Dispose()\n        {\n            Font.Dispose();\n        }\n\n        public int Size { get; }\n        public string FontFamily { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Drawing/DrawingFrame.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.Runtime.InteropServices;\nusing System.Threading.Tasks;\nusing Captura.Native;\n\nnamespace Captura.Windows.Gdi\n{\n    public class DrawingFrame : IBitmapFrame\n    {\n        public Bitmap Bitmap { get; }\n\n        public TimeSpan Timestamp { get; }\n\n        public DrawingFrame(Bitmap Bitmap, TimeSpan Timestamp)\n        {\n            this.Timestamp = Timestamp;\n            this.Bitmap = Bitmap;\n            Width = Bitmap.Width;\n            Height = Bitmap.Height;\n        }\n\n        DrawingFrame() { }\n\n        public static IBitmapFrame DummyFrame { get; } = new DrawingFrame();\n\n        public void Dispose() => Bitmap.Dispose();\n\n        public int Width { get; }\n        public int Height { get; }\n\n        void Copy(Action<(IntPtr SrcPtr, int DestOffset, int Length)> Copier)\n        {\n            var bits = Bitmap.LockBits(new Rectangle(Point.Empty, Bitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);\n\n            try\n            {\n                var rowSize = Math.Abs(bits.Stride);\n\n                Parallel.For(0, Height, Y =>\n                {\n                    Copier((IntPtr.Add(bits.Scan0, Y * bits.Stride), Y * rowSize, rowSize));\n                });\n            }\n            finally\n            {\n                Bitmap.UnlockBits(bits);\n            }\n        }\n\n        public void CopyTo(byte[] Buffer)\n        {\n            Copy(Param =>\n            {\n                var (srcPtr, destOffset, length) = Param;\n\n                Marshal.Copy(srcPtr, Buffer, destOffset, length);\n            });\n        }\n\n        public void CopyTo(IntPtr Buffer)\n        {\n            Copy(Param =>\n            {\n                var (srcPtr, destOffset, length) = Param;\n\n                Kernel32.CopyMemory(IntPtr.Add(Buffer, destOffset), srcPtr, length);\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Drawing/DrawingImage.cs",
    "content": "﻿using System.Drawing;\nusing System.IO;\n\nnamespace Captura.Windows.Gdi\n{\n    public class DrawingImage : IBitmapImage\n    {\n        public Image Image { get; }\n\n        public DrawingImage(Image Image)\n        {\n            this.Image = Image;\n        }\n\n        public void Dispose()\n        {\n            Image.Dispose();\n        }\n\n        public int Width => Image.Width;\n        public int Height => Image.Height;\n\n        public void Save(string FileName, ImageFormats Format)\n        {\n            Image.Save(FileName, Format.ToDrawingImageFormat());\n        }\n\n        public void Save(Stream Stream, ImageFormats Format)\n        {\n            Image.Save(Stream, Format.ToDrawingImageFormat());\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Drawing/DrawingImagingSystem.cs",
    "content": "﻿using System.Drawing;\nusing System.IO;\n\nnamespace Captura.Windows.Gdi\n{\n    class DrawingImagingSystem : IImagingSystem\n    {\n        public IBitmapImage CreateBitmap(int Width, int Height)\n        {\n            return new DrawingImage(new Bitmap(Width, Height));\n        }\n\n        public IBitmapImage LoadBitmap(string FileName)\n        {\n            return new DrawingImage(new Bitmap(FileName));\n        }\n\n        public IBitmapImage LoadBitmap(Stream Stream)\n        {\n            return new DrawingImage(new Bitmap(Stream));\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Drawing/GraphicsBitmapLoader.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Drawing.Imaging;\n\nnamespace Captura.Windows.Gdi\n{\n    public class GraphicsBitmapLoader : IBitmapLoader\n    {\n        GraphicsBitmapLoader() { }\n\n        public static GraphicsBitmapLoader Instance { get; } = new GraphicsBitmapLoader();\n\n        public IBitmapImage CreateBitmapBgr32(Size Size, IntPtr MemoryData, int Stride)\n        {\n            var bmp = new Bitmap(Size.Width, Size.Height, Stride, PixelFormat.Format32bppRgb, MemoryData);\n\n            return new DrawingImage(bmp);\n        }\n\n        public IBitmapImage LoadBitmap(string FileName)\n        {\n            var bmp = new Bitmap(FileName);\n\n            return new DrawingImage(bmp);\n        }\n\n        public void Dispose() { }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Drawing/GraphicsEditor.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Drawing.Drawing2D;\nusing System.Drawing.Imaging;\n\nnamespace Captura.Windows.Gdi\n{\n    public class GraphicsEditor : IEditableFrame\n    {\n        readonly Bitmap _image;\n        readonly Graphics _graphics;\n\n        public GraphicsEditor(Bitmap Image)\n        {\n            _image = Image;\n\n            _graphics = Graphics.FromImage(Image);\n\n            _graphics.SmoothingMode = SmoothingMode.AntiAlias;\n        }\n\n        public IBitmapFrame GenerateFrame(TimeSpan Timestamp)\n        {\n            Dispose();\n\n            return new DrawingFrame(_image, Timestamp);\n        }\n\n        public IBitmapImage CreateBitmapBgr32(Size Size, IntPtr MemoryData, int Stride)\n        {\n            return GraphicsBitmapLoader.Instance.CreateBitmapBgr32(Size, MemoryData, Stride);\n        }\n\n        public IBitmapImage LoadBitmap(string FileName)\n        {\n            return GraphicsBitmapLoader.Instance.LoadBitmap(FileName);\n        }\n\n        public void DrawLine(Point Start, Point End, Color Color, float Width)\n        {\n            _graphics.DrawLine(new Pen(new SolidBrush(Color), Width), Start, End);\n        }\n\n        public void DrawArrow(Point Start, Point End, Color Color, float Width)\n        {\n            using var pen = new Pen(new SolidBrush(Color), Width)\n            {\n                EndCap = LineCap.ArrowAnchor\n            };\n\n            _graphics.DrawLine(pen, Start, End);\n        }\n\n        public void DrawImage(IBitmapImage Image, RectangleF? Region, int Opacity = 100)\n        {\n            if (!(Image is DrawingImage drawingImage))\n                return;\n\n            var img = drawingImage.Image;\n\n            var region = Region is RectangleF r\n                ? new Rectangle((int)r.X, (int)r.Y, (int)r.Width, (int)r.Height)\n                : new Rectangle(Point.Empty, img.Size);\n\n            if (Opacity < 100)\n            {\n                var colormatrix = new ColorMatrix\n                {\n                    Matrix33 = Opacity / 100.0f\n                };\n\n                var imgAttribute = new ImageAttributes();\n                imgAttribute.SetColorMatrix(colormatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);\n\n                _graphics.DrawImage(img, region, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgAttribute);\n            }\n            else _graphics.DrawImage(img, region);\n        }\n\n        public void FillRectangle(Color Color, RectangleF Rectangle)\n        {\n            _graphics.FillRectangle(new SolidBrush(Color), Rectangle);\n        }\n\n        public void FillRectangle(Color Color, RectangleF Rectangle, int CornerRadius)\n        {\n            _graphics.FillRoundedRectangle(new SolidBrush(Color), Rectangle, CornerRadius);\n        }\n\n        public void FillEllipse(Color Color, RectangleF Rectangle)\n        {\n            _graphics.FillEllipse(new SolidBrush(Color), Rectangle);\n        }\n\n        public void DrawEllipse(Color Color, float StrokeWidth, RectangleF Rectangle)\n        {\n            _graphics.DrawEllipse(new Pen(Color, StrokeWidth), Rectangle);\n        }\n\n        public void DrawRectangle(Color Color, float StrokeWidth, RectangleF Rectangle)\n        {\n            _graphics.DrawRectangle(new Pen(Color, StrokeWidth), Rectangle.X, Rectangle.Y, Rectangle.Width, Rectangle.Height);\n        }\n\n        public void DrawRectangle(Color Color, float StrokeWidth, RectangleF Rectangle, int CornerRadius)\n        {\n            _graphics.DrawRoundedRectangle(new Pen(Color, StrokeWidth), Rectangle, CornerRadius);\n        }\n\n        public IFont GetFont(string FontFamily, int Size)\n        {\n            return new DrawingFont(FontFamily, Size);\n        }\n\n        public SizeF MeasureString(string Text, IFont Font)\n        {\n            if (Font is DrawingFont font)\n            {\n                return _graphics.MeasureString(Text, font.Font, PointF.Empty, StringFormat.GenericTypographic);\n            }\n\n            return SizeF.Empty;\n        }\n\n        public void DrawString(string Text, IFont Font, Color Color, RectangleF LayoutRectangle)\n        {\n            if (Font is DrawingFont font)\n            {\n                _graphics.DrawString(Text, font.Font, new SolidBrush(Color), LayoutRectangle, StringFormat.GenericTypographic);\n            }\n        }\n\n        public float Width => _graphics.VisibleClipBounds.Width;\n\n        public float Height => _graphics.VisibleClipBounds.Height;\n\n        public void Dispose()\n        {\n            _graphics.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Imaging/Drawing/GraphicsExtensions.cs",
    "content": "﻿using System.Drawing;\nusing System.Drawing.Drawing2D;\nusing System.Drawing.Imaging;\nusing Captura.Native;\n\nnamespace Captura.Windows.Gdi\n{\n    static class GraphicsExtensions\n    {\n        public static Rectangle Even(this Rectangle Rect)\n        {\n            if (Rect.Width % 2 == 1)\n                --Rect.Width;\n\n            if (Rect.Height % 2 == 1)\n                --Rect.Height;\n\n            return Rect;\n        }\n\n        /// <summary>\n        /// Removes the Pixels on Edges matching TrimColor(default is Transparent) from the Image\n        /// </summary>\n        internal static unsafe Bitmap CropEmptyEdges(this Bitmap Image, Color TrimColor = default)\n        {\n            if (Image == null)\n                return null;\n\n            int sizeX = Image.Width,\n                sizeY = Image.Height;\n\n            var r = new RECT(-1);\n\n            using (var b = new UnsafeBitmap(Image))\n            {\n                for (int x = 0, y = 0; ;)\n                {\n                    var pixel = b[x, y];\n\n                    bool Condition()\n                    {\n                        return TrimColor.A == 0\n                               && pixel->Alpha != 0\n                               ||\n                               TrimColor.R != pixel->Red\n                               && TrimColor.G != pixel->Green\n                               && TrimColor.B != pixel->Blue;\n                    }\n\n                    if (r.Left == -1)\n                    {\n                        if (Condition())\n                        {\n                            r.Left = x;\n\n                            x = 0;\n                            y = 0;\n\n                            continue;\n                        }\n\n                        if (y == sizeY - 1)\n                        {\n                            x++;\n                            y = 0;\n                        }\n                        else y++;\n\n                        continue;\n                    }\n\n                    if (r.Top == -1)\n                    {\n                        if (Condition())\n                        {\n                            r.Top = y;\n\n                            x = sizeX - 1;\n                            y = 0;\n\n                            continue;\n                        }\n\n                        if (x == sizeX - 1)\n                        {\n                            y++;\n                            x = 0;\n                        }\n                        else x++;\n\n                        continue;\n                    }\n\n                    if (r.Right == -1)\n                    {\n                        if (Condition())\n                        {\n                            r.Right = x + 1;\n\n                            x = 0;\n                            y = sizeY - 1;\n\n                            continue;\n                        }\n\n                        if (y == sizeY - 1)\n                        {\n                            x--;\n                            y = 0;\n                        }\n                        else y++;\n\n                        continue;\n                    }\n\n                    if (r.Bottom != -1)\n                        continue;\n\n                    if (Condition())\n                    {\n                        r.Bottom = y + 1;\n                        break;\n                    }\n\n                    if (x == sizeX - 1)\n                    {\n                        y--;\n                        x = 0;\n                    }\n                    else x++;\n                }\n            }\n\n            if (r.Left >= r.Right || r.Top >= r.Bottom)\n                return null;\n\n            var final = Image.Clone(r.ToRectangle(), Image.PixelFormat);\n\n            Image.Dispose();\n\n            return final;\n        }\n\n        /// <summary>\n        /// Creates a Transparent Bitmap from a combination of a Bitmap on a White Background and another on a Black Background\n        /// </summary>\n        internal static unsafe Bitmap DifferentiateAlpha(Bitmap WhiteBitmap, Bitmap BlackBitmap)\n        {\n            if (WhiteBitmap == null || BlackBitmap == null || WhiteBitmap.Size != BlackBitmap.Size)\n                return null;\n\n            int sizeX = WhiteBitmap.Width,\n                sizeY = WhiteBitmap.Height;\n\n            var final = new Bitmap(sizeX, sizeY, PixelFormat.Format32bppArgb);\n\n            var empty = true;\n\n            using (var a = new UnsafeBitmap(WhiteBitmap))\n            using (var b = new UnsafeBitmap(BlackBitmap))\n            using (var f = new UnsafeBitmap(final))\n            {\n                byte ToByte(int I) => (byte)(I > 255 ? 255 : (I < 0 ? 0 : I));\n\n                for (var y = 0; y < sizeY; ++y)\n                    for (var x = 0; x < sizeX; ++x)\n                    {\n                        PixelData* pixelA = a[x, y],\n                            pixelB = b[x, y],\n                            pixelF = f[x, y];\n\n                        pixelF->Alpha = ToByte((pixelB->Red - pixelA->Red + 255\n                                                + pixelB->Green - pixelA->Green + 255\n                                                + pixelB->Blue - pixelA->Blue + 255) / 3);\n\n                        if (pixelF->Alpha > 0)\n                        {\n                            // Following math creates an image optimized to be displayed on a black background\n                            pixelF->Red = ToByte(255 * pixelB->Red / pixelF->Alpha);\n                            pixelF->Green = ToByte(255 * pixelB->Green / pixelF->Alpha);\n                            pixelF->Blue = ToByte(255 * pixelB->Blue / pixelF->Alpha);\n\n                            if (empty)\n                                empty = false;\n                        }\n                    }\n            }\n\n            return empty ? null : final;\n        }\n\n        static GraphicsPath RoundedRect(RectangleF Bounds, int Radius)\n        {\n            var path = new GraphicsPath();\n\n            if (Radius == 0)\n            {\n                path.AddRectangle(Bounds);\n                return path;\n            }\n\n            var diameter = Radius * 2;\n            var arc = new RectangleF(Bounds.Location, new Size(diameter, diameter));\n\n            // top left arc  \n            path.AddArc(arc, 180, 90);\n\n            // top right arc  \n            arc.X = Bounds.Right - diameter;\n            path.AddArc(arc, 270, 90);\n\n            // bottom right arc  \n            arc.Y = Bounds.Bottom - diameter;\n            path.AddArc(arc, 0, 90);\n\n            // bottom left arc \n            arc.X = Bounds.Left;\n            path.AddArc(arc, 90, 90);\n\n            path.CloseFigure();\n            return path;\n        }\n\n        public static void DrawRoundedRectangle(this Graphics Graphics, Pen Pen, RectangleF Bounds, int CornerRadius)\n        {\n            using var path = RoundedRect(Bounds, CornerRadius);\n            Graphics.DrawPath(Pen, path);\n        }\n\n        public static void FillRoundedRectangle(this Graphics Graphics, Brush Brush, RectangleF Bounds, int CornerRadius)\n        {\n            using var path = RoundedRect(Bounds, CornerRadius);\n            Graphics.FillPath(Brush, path);\n        }\n\n        public static ImageFormat ToDrawingImageFormat(this ImageFormats Format)\n        {\n            switch (Format)\n            {\n                case ImageFormats.Jpg:\n                    return ImageFormat.Jpeg;\n\n                case ImageFormats.Png:\n                    return ImageFormat.Png;\n\n                case ImageFormats.Gif:\n                    return ImageFormat.Gif;\n\n                case ImageFormats.Bmp:\n                    return ImageFormat.Bmp;\n\n                default:\n                    return ImageFormat.Png;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/MediaFoundation/MfAudioItem.cs",
    "content": "﻿using Captura.Audio;\nusing SharpDX.MediaFoundation;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Captura.Windows.MediaFoundation\n{\n    class MfAudioItem : IAudioWriterItem\n    {\n        Guid _mediaSubtype;\n\n        MfAudioItem(string Name, string Extension, Guid MediaSubtype)\n        {\n            this.Name = Name + \" (Media Foundation)\";\n            this.Extension = Extension;\n\n            _mediaSubtype = MediaSubtype;\n        }\n\n        public static IEnumerable<MfAudioItem> Items { get; } = new[]\n        {\n            new MfAudioItem(\"AAC\", \".aac\", AudioFormatGuids.Aac)\n        };\n\n        public string Name { get; }\n\n        public string Extension { get; }\n\n        public override string ToString() => Name;\n\n        public IAudioFileWriter GetAudioFileWriter(string FileName, WaveFormat Wf, int AudioQuality)\n        {\n            return new MfAudioWriter(FileName, _mediaSubtype, Wf, AudioQuality);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/MediaFoundation/MfAudioWriter.cs",
    "content": "﻿using Captura.Audio;\nusing SharpDX.MediaFoundation;\nusing System;\nusing System.Runtime.InteropServices;\n\nnamespace Captura.Windows.MediaFoundation\n{\n    class MfAudioWriter : IAudioFileWriter\n    {\n        SinkWriter _writer;\n        const int StreamIndex = 0;\n        const int TenPower7 = 10_000_000;\n        readonly long _audioInBytesPerSecond;\n        long _audioWritten;\n\n        public MfAudioWriter(string FileName,\n            Guid MediaSubtype,\n            WaveFormat Wf,\n            int AudioQuality)\n        {\n            _writer = MediaFactory.CreateSinkWriterFromURL(FileName, null, null);\n\n            _audioInBytesPerSecond = Wf.SampleRate * Wf.Channels * Wf.BitsPerSample / 8;\n\n            using (var audioTypeOut = MfWriter.GetMediaType(Wf))\n            {\n                audioTypeOut.Set(MediaTypeAttributeKeys.Subtype, MediaSubtype);\n                \n                if (MediaSubtype == AudioFormatGuids.Aac)\n                {\n                    audioTypeOut.Set(MediaTypeAttributeKeys.AudioAvgBytesPerSecond, MfWriter.GetAacBitrate(AudioQuality));\n                }\n\n                _writer.AddStream(audioTypeOut, out _);\n            }\n\n            using (var audioTypeIn = MfWriter.GetMediaType(Wf))\n            {\n                audioTypeIn.Set(MediaTypeAttributeKeys.Subtype, AudioFormatGuids.Pcm);\n                _writer.SetInputMediaType(StreamIndex, audioTypeIn, null);\n            }\n\n            _writer.BeginWriting();\n        }\n\n        public void Dispose()\n        {\n            _writer.Finalize();\n            _writer.Dispose();\n        }\n\n        public void Flush()\n        {\n            _writer.Flush(StreamIndex);\n        }\n\n        public void Write(byte[] Data, int Offset, int Count)\n        {\n            using (var buffer = MediaFactory.CreateMemoryBuffer(Count))\n            {\n                var data = buffer.Lock(out _, out _);\n\n                Marshal.Copy(Data, Offset, data, Count);\n\n                buffer.CurrentLength = Count;\n\n                buffer.Unlock();\n\n                using var sample = MediaFactory.CreateVideoSampleFromSurface(null);\n                sample.AddBuffer(buffer);\n\n                sample.SampleTime = _audioWritten * TenPower7 / _audioInBytesPerSecond;\n                sample.SampleDuration = Count * TenPower7 / _audioInBytesPerSecond;\n\n                _writer.WriteSample(StreamIndex, sample);\n            }\n\n            _audioWritten += Count;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/MediaFoundation/MfColorConverter.cs",
    "content": "﻿using MediaFoundation.Transform;\nusing SharpDX.Direct3D11;\nusing SharpDX.DXGI;\nusing SharpDX.MediaFoundation;\nusing System;\nusing System.Runtime.InteropServices;\nusing Device = SharpDX.Direct3D11.Device;\n\nnamespace Captura.Windows.MediaFoundation\n{\n    public class MfColorConverter : IDisposable\n    {\n        Transform _colorConverter;\n        DXGIDeviceManager _deviceMan;\n\n        public MfColorConverter(int Width, int Height, Device Device)\n        {\n            var transforms = MediaFactory.FindTransform(TransformCategoryGuids.VideoProcessor, TransformEnumFlag.All);\n            _colorConverter = transforms[0].ActivateObject<Transform>();\n\n            _deviceMan = new DXGIDeviceManager();\n            _deviceMan.ResetDevice(Device);\n\n            _colorConverter.ProcessMessage(TMessageType.SetD3DManager, _deviceMan.NativePointer);\n\n            using (var mediaTypeIn = new MediaType())\n            {\n                mediaTypeIn.Set(MediaTypeAttributeKeys.MajorType, MediaTypeGuids.Video);\n                mediaTypeIn.Set(MediaTypeAttributeKeys.Subtype, VideoFormatGuids.Rgb32);\n                mediaTypeIn.Set(MediaTypeAttributeKeys.FrameSize, MfWriter.PackLong(Width, Height));\n                mediaTypeIn.Set(MediaTypeAttributeKeys.DefaultStride, Width * 4);\n                mediaTypeIn.Set(MediaTypeAttributeKeys.FixedSizeSamples, 1);\n                mediaTypeIn.Set(MediaTypeAttributeKeys.SampleSize, Width * Height * 4);\n\n                _colorConverter.SetInputType(0, mediaTypeIn, 0);\n            }\n\n            var outputStride = Width * 12 / 8;\n            var outputSampleSize = Height * outputStride;\n\n            using (var mediaTypeOut = new MediaType())\n            {\n                mediaTypeOut.Set(MediaTypeAttributeKeys.MajorType, MediaTypeGuids.Video);\n                mediaTypeOut.Set(MediaTypeAttributeKeys.Subtype, VideoFormatGuids.NV12);\n                mediaTypeOut.Set(MediaTypeAttributeKeys.FrameSize, MfWriter.PackLong(Width, Height));\n                mediaTypeOut.Set(MediaTypeAttributeKeys.DefaultStride, outputStride);\n                mediaTypeOut.Set(MediaTypeAttributeKeys.FixedSizeSamples, 1);\n                mediaTypeOut.Set(MediaTypeAttributeKeys.SampleSize, outputSampleSize);\n\n                _colorConverter.SetOutputType(0, mediaTypeOut, 0);\n            }\n\n            _colorConverter.ProcessMessage(TMessageType.NotifyBeginStreaming, IntPtr.Zero);\n\n            _copyTexture = new Texture2D(Device, new Texture2DDescription\n            {\n                CpuAccessFlags = CpuAccessFlags.None,\n                BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,\n                Format = Format.B8G8R8A8_UNorm,\n                Width = Width,\n                Height = Height,\n                OptionFlags = ResourceOptionFlags.None,\n                MipLevels = 1,\n                ArraySize = 1,\n                SampleDescription = { Count = 1, Quality = 0 },\n                Usage = ResourceUsage.Default\n            });\n\n            _inputSample = MediaFactory.CreateVideoSampleFromSurface(null);\n\n            // Create the media buffer from the texture\n            MediaFactory.CreateDXGISurfaceBuffer(typeof(Texture2D).GUID, _copyTexture, 0, false, out var inputBuffer);\n\n            using (var buffer2D = inputBuffer.QueryInterface<Buffer2D>())\n                inputBuffer.CurrentLength = buffer2D.ContiguousLength;\n\n            // Attach the created buffer to the sample\n            _inputSample.AddBuffer(inputBuffer);\n        }\n\n        int _frameNumber;\n\n        Texture2D _copyTexture;\n        Sample _inputSample;\n\n        public void Convert(Texture2D Texture, byte[] Output)\n        {\n            Texture.Device.ImmediateContext.CopyResource(Texture, _copyTexture);\n\n            _inputSample.SampleTime = _frameNumber++ * 1_000_000;\n\n            _colorConverter.ProcessInput(0, _inputSample, 0);\n\n            var buf = new MFTOutputDataBuffer[1];\n\n            // HACK: Need to use Media Foundation .NET here due to bug in SharpDX.MediaFoundation (no longer maintained).\n            // I think the output data buffer is not [Out] marshalled.\n            ((IMFTransform)Marshal.GetObjectForIUnknown(_colorConverter.NativePointer)).ProcessOutput(0, 1, buf, out _);\n\n            using var sample = new Sample(buf[0].pSample);\n            using var buffer = sample.GetBufferByIndex(0);\n            var ptr = buffer.Lock(out _, out _);\n\n            Marshal.Copy(ptr, Output, 0, Output.Length);\n\n            buffer.Unlock();\n        }\n\n        public void Dispose()\n        {\n            _colorConverter.ProcessMessage(TMessageType.NotifyEndOfStream, IntPtr.Zero);\n\n            _inputSample.Dispose();\n\n            _copyTexture.Dispose();\n\n            _colorConverter.Dispose();\n            _colorConverter = null;\n\n            _deviceMan.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/MediaFoundation/MfItem.cs",
    "content": "﻿using Captura.Video;\nusing SharpDX.Direct3D11;\n\nnamespace Captura.Windows.MediaFoundation\n{\n    public class MfItem : IVideoWriterItem\n    {\n        readonly Device _device;\n\n        public string Extension => \".mp4\";\n        public string Description { get; } = \"Encode to Mp4: H.264 with AAC audio using Media Foundation Hardware encoder\";\n\n        readonly string _name = \"MF\";\n\n        public MfItem(Device Device)\n        {\n            _device = Device;\n        }\n\n        public override string ToString() => _name;\n\n        public virtual IVideoFileWriter GetVideoFileWriter(VideoWriterArgs Args)\n        {\n            return new MfWriter(Args, _device);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/MediaFoundation/MfManager.cs",
    "content": "﻿using SharpDX.MediaFoundation;\n\nnamespace Captura.Windows.MediaFoundation\n{\n    public static class MfManager\n    {\n        public static void Startup()\n        {\n            MediaManager.Startup();\n        }\n        public static void Shutdown()\n        {\n            MediaFactory.Shutdown();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/MediaFoundation/MfWriter.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\nusing Captura.Audio;\nusing Captura.Native;\nusing Captura.Video;\nusing Captura.Windows.DirectX;\nusing SharpDX;\nusing SharpDX.Direct3D11;\nusing SharpDX.DXGI;\nusing SharpDX.MediaFoundation;\nusing Device = SharpDX.Direct3D11.Device;\n\nnamespace Captura.Windows.MediaFoundation\n{\n    public class MfWriter : IVideoFileWriter\n    {\n        readonly Device _device;\n        const int BitRate = 8_000_000;\n        readonly Guid _encodingFormat = VideoFormatGuids.H264;\n        readonly Guid _encodedAudioFormat = AudioFormatGuids.Aac;\n        readonly long _frameDuration;\n        readonly SinkWriter _writer;\n\n        static readonly MediaAttributeKey<RateControlMode> RateControlModeKey = new MediaAttributeKey<RateControlMode>(\"1c0608e9-370c-4710-8a58-cb6181c42423\");\n        static readonly MediaAttributeKey<int> QualityKey = new MediaAttributeKey<int>(\"fcbf57a3-7ea5-4b0c-9644-69b40c39c391\");\n\n        const int VideoStreamIndex = 0;\n        const int AudioStreamIndex = 1;\n\n        const int TenPower7 = 10_000_000;\n        readonly int _bufferSize;\n        readonly long _audioInBytesPerSecond;\n\n        long _frameNumber = -1;\n\n        // Keep this separate. First frame might be a RepeatFrame.\n        bool _first = true;\n\n        public static long PackLong(int Left, int Right)\n        {\n            return new PackedLong\n            {\n                Low = Right,\n                High = Left\n            }.Long;\n        }\n\n        MediaAttributes GetSinkWriterAttributes(Device Device)\n        {\n            var attr = new MediaAttributes(6);\n\n            attr.Set(SinkWriterAttributeKeys.ReadwriteEnableHardwareTransforms, 1);\n            attr.Set(SinkWriterAttributeKeys.ReadwriteDisableConverters, 0);\n            attr.Set(TranscodeAttributeKeys.TranscodeContainertype, TranscodeContainerTypeGuids.Mpeg4);\n            attr.Set(SinkWriterAttributeKeys.LowLatency, true);\n\n            var devMan = new DXGIDeviceManager();\n            devMan.ResetDevice(Device);\n            attr.Set(SinkWriterAttributeKeys.D3DManager, devMan);\n\n            return attr;\n        }\n\n        public MfWriter(VideoWriterArgs Args, Device Device)\n        {\n            var inputFormat = Args.ImageProvider.DummyFrame is Texture2DFrame\n                ? VideoFormatGuids.NV12\n                : VideoFormatGuids.Rgb32;\n\n            _device = Device;\n\n            _frameDuration = TenPower7 / Args.FrameRate;\n\n            var attr = GetSinkWriterAttributes(Device);\n\n            _writer = MediaFactory.CreateSinkWriterFromURL(Args.FileName, null, attr);\n\n            var w = Args.ImageProvider.Width;\n            var h = Args.ImageProvider.Height;\n            _bufferSize = w * h * 4;\n\n            using (var mediaTypeOut = new MediaType())\n            {\n                mediaTypeOut.Set(MediaTypeAttributeKeys.MajorType, MediaTypeGuids.Video);\n                mediaTypeOut.Set(MediaTypeAttributeKeys.Subtype, _encodingFormat);\n                mediaTypeOut.Set(MediaTypeAttributeKeys.AvgBitrate, BitRate);\n                mediaTypeOut.Set(MediaTypeAttributeKeys.InterlaceMode, (int)VideoInterlaceMode.Progressive);\n                mediaTypeOut.Set(MediaTypeAttributeKeys.FrameSize, PackLong(w, h));\n                mediaTypeOut.Set(MediaTypeAttributeKeys.FrameRate, PackLong(Args.FrameRate, 1));\n                mediaTypeOut.Set(MediaTypeAttributeKeys.PixelAspectRatio, PackLong(1, 1));\n                _writer.AddStream(mediaTypeOut, out _);\n            }\n\n            using (var mediaTypeIn = new MediaType())\n            {\n                mediaTypeIn.Set(MediaTypeAttributeKeys.MajorType, MediaTypeGuids.Video);\n                mediaTypeIn.Set(MediaTypeAttributeKeys.Subtype, inputFormat);\n                mediaTypeIn.Set(MediaTypeAttributeKeys.InterlaceMode, (int)VideoInterlaceMode.Progressive);\n                mediaTypeIn.Set(MediaTypeAttributeKeys.FrameSize, PackLong(w, h));\n                mediaTypeIn.Set(MediaTypeAttributeKeys.FrameRate, PackLong(Args.FrameRate, 1));\n                mediaTypeIn.Set(MediaTypeAttributeKeys.PixelAspectRatio, PackLong(1, 1));\n                mediaTypeIn.Set(MediaTypeAttributeKeys.AllSamplesIndependent, 1);\n\n                var encoderParams = new MediaAttributes(2);\n                encoderParams.Set(RateControlModeKey, RateControlMode.Quality);\n                encoderParams.Set(QualityKey, Args.VideoQuality);\n                _writer.SetInputMediaType(VideoStreamIndex, mediaTypeIn, encoderParams);\n            }\n\n            if (Args.AudioProvider != null)\n            {\n                var wf = Args.AudioProvider.WaveFormat;\n                _audioInBytesPerSecond = wf.SampleRate * wf.Channels * wf.BitsPerSample / 8;\n\n                using (var audioTypeOut = GetMediaType(wf))\n                {\n                    audioTypeOut.Set(MediaTypeAttributeKeys.Subtype, _encodedAudioFormat);\n                    audioTypeOut.Set(MediaTypeAttributeKeys.AudioAvgBytesPerSecond, GetAacBitrate(Args.AudioQuality));\n                    _writer.AddStream(audioTypeOut, out _);\n                }\n\n                using var audioTypeIn = GetMediaType(wf);\n                audioTypeIn.Set(MediaTypeAttributeKeys.Subtype, AudioFormatGuids.Pcm);\n                _writer.SetInputMediaType(AudioStreamIndex, audioTypeIn, null);\n            }\n\n            _writer.BeginWriting();\n\n            _copyTexture = new Texture2D(Device, new Texture2DDescription\n            {\n                CpuAccessFlags = CpuAccessFlags.Read,\n                BindFlags = BindFlags.None,\n                Format = Format.B8G8R8A8_UNorm,\n                Width = w,\n                Height = h,\n                OptionFlags = ResourceOptionFlags.None,\n                MipLevels = 1,\n                ArraySize = 1,\n                SampleDescription = { Count = 1, Quality = 0 },\n                Usage = ResourceUsage.Staging\n            });\n\n            _sample = MediaFactory.CreateVideoSampleFromSurface(null);\n                \n            // Create the media buffer from the texture\n            MediaFactory.CreateDXGISurfaceBuffer(typeof(Texture2D).GUID, _copyTexture, 0, false, out _mediaBuffer);\n\n            using (var buffer2D = _mediaBuffer.QueryInterface<Buffer2D>())\n                _mediaBuffer.CurrentLength = buffer2D.ContiguousLength;\n\n            // Attach the created buffer to the sample\n            _sample.AddBuffer(_mediaBuffer);\n        }\n\n        public static MediaType GetMediaType(WaveFormat Wf)\n        {\n            var mediaType = new MediaType();\n            \n            mediaType.Set(MediaTypeAttributeKeys.MajorType, MediaTypeGuids.Audio);\n            mediaType.Set(MediaTypeAttributeKeys.AudioNumChannels, Wf.Channels);\n            mediaType.Set(MediaTypeAttributeKeys.AudioBitsPerSample, Wf.BitsPerSample);\n            mediaType.Set(MediaTypeAttributeKeys.AudioSamplesPerSecond, Wf.SampleRate);\n\n            return mediaType;\n        }\n\n        public static int GetAacBitrate(int AudioQuality)\n        {\n            var i = (AudioQuality - 1) / 25;\n\n            return new[]\n            {\n                12_000,\n                16_000,\n                20_000,\n                24_000\n            }[i];\n        }\n\n        readonly object _syncLock = new object();\n\n        public void Write(Sample Sample)\n        {\n            lock (_syncLock)\n            {\n                if (_disposed)\n                    return;\n\n                Sample.SampleTime = _frameNumber * _frameDuration;\n                Sample.SampleDuration = _frameDuration;\n                \n                if (_first)\n                {\n                    _writer.SendStreamTick(VideoStreamIndex, Sample.SampleTime);\n                    Sample.Set(SampleAttributeKeys.Discontinuity, true);\n                    _first = false;\n                }\n                _writer.WriteSample(VideoStreamIndex, Sample);\n            }\n        }\n\n        Texture2D _copyTexture;\n        Sample _sample;\n        MediaBuffer _mediaBuffer;\n\n        void Write(Texture2D Texture)\n        {\n            _device.ImmediateContext.CopyResource(Texture, _copyTexture);\n\n            Write(_sample);\n        }\n\n        bool _disposed;\n\n        public void Dispose()\n        {\n            lock (_syncLock)\n            {\n                _disposed = true;\n                \n                const int noSamplesProcessedHResult = unchecked((int) 0xC00D4A44);\n\n                try\n                {\n                    _writer.Finalize();\n                }\n                // This error happens if recording is stopped before any samples are written\n                catch (SharpDXException e) when (e.HResult == noSamplesProcessedHResult) { }\n\n                _writer.Dispose();\n\n                _copyTexture.Dispose();\n                _copyTexture = null;\n\n                _sample.Dispose();\n                _sample = null;\n\n                _mediaBuffer.Dispose();\n                _mediaBuffer = null;\n            }\n        }\n\n        public void WriteFrame(IBitmapFrame Image)\n        {\n            ++_frameNumber;\n\n            if (Image is RepeatFrame)\n                return;\n\n            Image = Image.Unwrap();\n\n            using (Image)\n            {\n                if (Image is Texture2DFrame frame)\n                {\n                    Write(frame.Texture);\n                }\n                else\n                {\n                    using var buffer = MediaFactory.CreateMemoryBuffer(_bufferSize);\n                    var data = buffer.Lock(out _, out _);\n\n                    Image.CopyTo(data);\n\n                    buffer.CurrentLength = _bufferSize;\n\n                    buffer.Unlock();\n\n                    using var sample = MediaFactory.CreateVideoSampleFromSurface(null);\n                    sample.AddBuffer(buffer);\n\n                    Write(sample);\n                }\n            }\n        }\n\n        public bool SupportsAudio => true;\n\n        long _audioWritten;\n\n        public void WriteAudio(byte[] Buffer, int Offset, int Length)\n        {\n            using (var buffer = MediaFactory.CreateMemoryBuffer(Length))\n            {\n                var data = buffer.Lock(out _, out _);\n\n                Marshal.Copy(Buffer, Offset, data, Length);\n\n                buffer.CurrentLength = Length;\n\n                buffer.Unlock();\n\n                using var sample = MediaFactory.CreateVideoSampleFromSurface(null);\n                sample.AddBuffer(buffer);\n\n                sample.SampleTime = _audioWritten * TenPower7 / _audioInBytesPerSecond;\n                sample.SampleDuration = Length * TenPower7 / _audioInBytesPerSecond;\n\n                _writer.WriteSample(AudioStreamIndex, sample);\n            }\n\n            _audioWritten += Length;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/MediaFoundation/MfWriterProvider.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Captura.Video;\nusing SharpDX.Direct3D;\nusing SharpDX.Direct3D11;\n\nnamespace Captura.Windows.MediaFoundation\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class MfWriterProvider : IVideoWriterProvider\n    {\n        readonly Device _device;\n\n        public MfWriterProvider()\n        {\n            _device = new Device(DriverType.Hardware, DeviceCreationFlags.BgraSupport);\n        }\n\n        public string Name => \"MF\";\n\n        public IEnumerator<IVideoWriterItem> GetEnumerator()\n        {\n            yield return new MfItem(_device);\n        }\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        public override string ToString() => Name;\n\n        public IVideoWriterItem ParseCli(string Cli)\n        {\n            return Cli == \"mf\" ? this.First() : null;\n        }\n\n        public string Description => \"Encode to Mp4: H.264 with AAC audio using Media Foundation Hardware encoder\";\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/MediaFoundation/PackedLong.cs",
    "content": "﻿using System.Runtime.InteropServices;\n\nnamespace Captura.Native\n{\n    [StructLayout(LayoutKind.Explicit)]\n    public class PackedLong\n    {\n        [FieldOffset(0)]\n        public long Long;\n\n        [FieldOffset(0)]\n        public int Low;\n\n        [FieldOffset(sizeof(int))]\n        public int High;\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/MediaFoundation/RateControlMode.cs",
    "content": "﻿namespace Captura.Windows.MediaFoundation\n{\n    enum RateControlMode\n    {\n        CBR,\n        PeakConstrainedVBR,\n        UnconstrainedVBR,\n        Quality,\n        LowDelayVBR,\n        GlobalVBR,\n        GlobalLowDelayVBR\n    };\n}"
  },
  {
    "path": "src/Captura.Windows/Native/DwmApi.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\nnamespace Captura.Native\n{\n    static class DwmApi\n    {\n        const string DllName = \"dwmapi.dll\";\n\n        [DllImport(DllName)]\n        public static extern int DwmGetWindowAttribute(IntPtr Window, int Attribute, out bool Value, int Size);\n\n        [DllImport(DllName)]\n        public static extern int DwmGetWindowAttribute(IntPtr Window, int Attribute, ref RECT Value, int Size);\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/EnumWindowsProc.cs",
    "content": "﻿using System;\n// ReSharper disable InconsistentNaming\n\nnamespace Captura.Native\n{\n    delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Enums/DrawIconExFlags.cs",
    "content": "﻿// ReSharper disable InconsistentNaming\n\nnamespace Captura.Native\n{\n    enum DrawIconExFlags\n    {\n        Compat = 0x04,\n        DefaultSize = 0x08,\n        Image = 0x02,\n        Mask = 0x01,\n        NoMirror = 0x10,\n        Normal = Image | Mask\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Enums/FileOperationFlags.cs",
    "content": "﻿using System;\n// ReSharper disable UnusedMember.Global\n\nnamespace Captura.Native\n{\n    [Flags]\n    enum FileOperationFlags\n    {\n        MultiDestFiles = 0x1,\n\n        ConfirmMouse = 0x2,\n        \n        /// <summary>\n        /// Don't create progress/report\n        /// </summary>\n        Silent = 0x4,\n\n        RenameOnCollission = 0x8,\n        \n        /// <summary>\n        /// Don't prompt the user.\n        /// </summary>\n        NoConfirmation = 0x10,\n        \n        /// <summary>\n        /// Fill in <see cref=\"ShFileOpStruct.NameMappings\"/>.\n        /// Must be freed using SHFreeNameMappings\n        /// </summary>\n        WantMappingHandle = 0x20,\n\n        AllowUndo = 0x40,\n        \n        /// <summary>\n        /// On *.*, do only files\n        /// </summary>\n        FilesOnly = 0x80,\n        \n        /// <summary>\n        /// Don't show names of files\n        /// </summary>\n        SimpleProgress = 0x100,\n        \n        /// <summary>\n        /// Don't confirm making any needed dirs\n        /// </summary>\n        NoConfirmMkdir = 0x200,\n        \n        /// <summary>\n        /// Don't put up error UI\n        /// </summary>\n        // ReSharper disable once InconsistentNaming\n        NoErrorUI = 0x400,\n        \n        /// <summary>\n        /// Dont copy NT file Security Attributes\n        /// </summary>\n        NoCopySecurityAttribs = 0x800,\n        \n        /// <summary>\n        /// Don't recurse into directories.\n        /// </summary>\n        NoRecursion = 0x1000,\n        \n        /// <summary>\n        /// Don't operate on connected elements.\n        /// </summary>\n        NoConnectedElements = 0x2000,\n        \n        /// <summary>\n        /// During delete operation, \n        /// warn if nuking instead of recycling (partially overrides <see cref=\"NoConfirmation\"/>)\n        /// </summary>\n        WantNukeWarning = 0x4000,\n        \n        /// <summary>\n        /// Treat reparse points as objects, not containers\n        /// </summary>\n        NoRecurseReparse = 0x8000\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Enums/FileOperationType.cs",
    "content": "﻿// ReSharper disable UnusedMember.Global\nnamespace Captura.Native\n{\n    enum FileOperationType\n    {\n        Move = 0x1,\n        Copy = 0x2,\n        Delete = 0x3,\n        Rename = 0x4\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Enums/GetWindowEnum.cs",
    "content": "﻿namespace Captura.Native\n{\n    enum GetWindowEnum\n    {\n        Owner = 4\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Enums/GetWindowLongValue.cs",
    "content": "﻿namespace Captura.Native\n{\n    enum GetWindowLongValue\n    {\n        Style = -16,\n        ExStyle = -20\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Enums/SetWindowPositionFlags.cs",
    "content": "﻿namespace Captura.Native\n{\n    enum SetWindowPositionFlags\n    {\n        ShowWindow = 0x400,\n        NoActivate = 0x0010\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Enums/WindowStyles.cs",
    "content": "﻿namespace Captura.Native\n{\n    enum WindowStyles : long\n    {\n        Child = 0x40000000,\n        ToolWindow = 0x00000080,\n        AppWindow = 0x00040000,\n        SizeBox = 0x00040000L\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Gdi32.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n// ReSharper disable InconsistentNaming\n\nnamespace Captura.Native\n{\n    static class Gdi32\n    {\n        const string DllName = \"gdi32.dll\";\n\n        [DllImport(DllName)]\n        public static extern bool DeleteObject(IntPtr hObject);\n\n        [DllImport(DllName)]\n        public static extern bool BitBlt(IntPtr hObject, int XDest, int YDest, int Width, int Height, IntPtr ObjectSource, int XSrc, int YSrc, int Op);\n\n        [DllImport(DllName)]\n        public static extern bool StretchBlt(IntPtr hObject, int XDest, int YDest, int WDest, int HDest, IntPtr ObjectSource, int XSrc, int YSrc, int WSrc, int HSrc, int Op);\n\n        [DllImport(DllName)]\n        public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int Width, int Height);\n\n        [DllImport(DllName)]\n        public static extern IntPtr CreateCompatibleDC(IntPtr hDC);\n\n        [DllImport(DllName)]\n        public static extern bool DeleteDC(IntPtr hDC);\n\n        [DllImport(DllName)]\n        public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Kernel32.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\nnamespace Captura.Native\n{\n    public class Kernel32\n    {\n        const string DllName = \"Kernel32\";\n\n        [DllImport(DllName)]\n        public static extern void CopyMemory(IntPtr Dest, IntPtr Src, int Count);\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Native/NativeExtensions.cs",
    "content": "﻿using System.Drawing;\n\nnamespace Captura.Native\n{\n    static class NativeExtensions\n    {\n        public static Rectangle ToRectangle(this RECT R) => Rectangle.FromLTRB(R.Left, R.Top, R.Right, R.Bottom);\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Shell32.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\nnamespace Captura.Native\n{\n    static class Shell32\n    {\n        const string DllName = \"shell32.dll\";\n\n        [DllImport(DllName, CharSet = CharSet.Unicode)]\n        public static extern int SHFileOperation(ref ShFileOpStruct FileOp);\n\n        public static int FileOperation(string Path, FileOperationType OperationType, FileOperationFlags Flags)\n        {\n            try\n            {\n                var fs = new ShFileOpStruct\n                {\n                    Func = OperationType,\n                    From = Path + '\\0' + '\\0',\n                    Flags = Flags\n                };\n\n                return SHFileOperation(ref fs);\n            }\n            catch (Exception)\n            {\n                return -1;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Structs/CursorInfo.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Runtime.InteropServices;\n// ReSharper disable FieldCanBeMadeReadOnly.Global\n\nnamespace Captura.Native\n{\n    [StructLayout(LayoutKind.Sequential)]\n    struct CursorInfo\n    {\n        public int cbSize;\n        public int flags;\n        public IntPtr hCursor;\n        public Point ptScreenPos;\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Structs/IconInfo.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n// ReSharper disable MemberCanBePrivate.Global\n// ReSharper disable FieldCanBeMadeReadOnly.Global\n\nnamespace Captura.Native\n{\n    [StructLayout(LayoutKind.Sequential)]\n    struct IconInfo\n    {\n        public bool fIcon;\n        public int xHotspot;\n        public int yHotspot;\n        public IntPtr hbmMask;\n        public IntPtr hbmColor;\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Structs/RECT.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\nnamespace Captura.Native\n{\n    [Serializable, StructLayout(LayoutKind.Sequential)]\n    // ReSharper disable once InconsistentNaming\n    struct RECT\n    {\n        public int Left;\n        public int Top;\n        public int Right;\n        public int Bottom;\n\n        public RECT(int Dimension)\n        {\n            Left = Top = Right = Bottom = Dimension;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/Structs/ShFileOpStruct.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n// ReSharper disable FieldCanBeMadeReadOnly.Global\n// ReSharper disable MemberCanBePrivate.Global\n\nnamespace Captura.Native\n{\n    [StructLayout(LayoutKind.Sequential)]\n    struct ShFileOpStruct\n    {\n        public IntPtr hwnd;\n\n        public FileOperationType Func;\n\n        [MarshalAs(UnmanagedType.LPWStr)]\n        public string From;\n\n        [MarshalAs(UnmanagedType.LPWStr)]\n        public string To;\n\n        public FileOperationFlags Flags;\n\n        [MarshalAs(UnmanagedType.Bool)]\n        public bool AnyOperationsAborted;\n\n        public IntPtr NameMappings;\n\n        [MarshalAs(UnmanagedType.LPWStr)]\n        public string ProgressTitle;\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/UnsafeBitmap.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.Runtime.InteropServices;\n\nnamespace Captura.Native\n{\n    [StructLayout(LayoutKind.Sequential)]\n    struct PixelData { public byte Blue, Green, Red, Alpha; }\n\n    unsafe class UnsafeBitmap : IDisposable\n    {\n        readonly Bitmap _inputBitmap;\n        BitmapData _bitmapData;\n        byte* _pBase;\n        readonly int _width;\n\n        public UnsafeBitmap(Bitmap InputBitmap) \n        {\n            _inputBitmap = InputBitmap;\n\n            var bounds = new Rectangle(Point.Empty, _inputBitmap.Size);\n\n            _width = bounds.Width * sizeof(PixelData);\n\n            if (_width % 4 != 0)\n                _width = 4 * (_width / 4 + 1);\n\n            //Lock Image\n            _bitmapData = _inputBitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);\n            _pBase = (byte*)_bitmapData.Scan0;\n        }\n\n        public PixelData* this[int X, int Y] => (PixelData*)(_pBase + Y * _width + X * sizeof(PixelData));\n\n        public void Dispose()\n        {\n            _inputBitmap.UnlockBits(_bitmapData);\n            _bitmapData = null;\n            _pBase = null;\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Native/User32.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\n// ReSharper disable InconsistentNaming\n\nnamespace Captura.Native\n{\n    static class User32\n    {\n        const string DllName = \"user32.dll\";\n\n        [DllImport(DllName)]\n        public static extern bool GetCursorPos(ref Point lpPoint);\n\n        [DllImport(DllName)]\n        public static extern bool DrawIconEx(IntPtr hDC,\n            int Left,\n            int Top,\n            IntPtr hIcon,\n            int Width,\n            int Height,\n            int StepIfAniCur,\n            IntPtr BrushForFlickerFreeDraw,\n            DrawIconExFlags Flags);\n\n        [DllImport(DllName)]\n        public static extern WindowStyles GetWindowLong(IntPtr hWnd, GetWindowLongValue nIndex);\n\n        [DllImport(DllName)]\n        public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);\n\n        [DllImport(DllName)]\n        public static extern bool IsWindow(IntPtr hWnd);\n\n        [DllImport(DllName)]\n        public static extern IntPtr GetDesktopWindow();\n\n        [DllImport(DllName)]\n        public static extern IntPtr GetForegroundWindow();\n\n        [DllImport(DllName)]\n        public static extern bool EnumWindows(EnumWindowsProc proc, IntPtr lParam);\n\n        [DllImport(DllName)]\n        public static extern bool EnumChildWindows(IntPtr hWnd, EnumWindowsProc proc, IntPtr lParam);\n\n        [DllImport(DllName)]\n        public static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount);\n\n        [DllImport(DllName)]\n        public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowEnum uCmd);\n\n        [DllImport(DllName)]\n        public static extern int GetWindowTextLength(IntPtr hWnd);\n\n        [DllImport(DllName)]\n        public static extern bool IsWindowVisible(IntPtr hWnd);\n\n        [DllImport(DllName)]\n        public static extern bool SetForegroundWindow(IntPtr hWnd);\n\n        [DllImport(DllName)]\n        public static extern bool IsIconic(IntPtr hWnd);\n\n        [DllImport(DllName)]\n        public static extern bool IsZoomed(IntPtr hWnd);\n\n        [DllImport(DllName)]\n        public static extern bool DestroyIcon(IntPtr hIcon);\n\n        [DllImport(DllName)]\n        public static extern IntPtr CopyIcon(IntPtr hIcon);\n\n        [DllImport(DllName)]\n        public static extern bool GetCursorInfo(ref CursorInfo pci);\n\n        [DllImport(DllName)]\n        public static extern bool GetIconInfo(IntPtr hIcon, out IconInfo piconinfo);\n\n        [DllImport(DllName)]\n        public static extern IntPtr GetDC(IntPtr hWnd);\n\n        [DllImport(DllName)]\n        public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);\n\n        [DllImport(DllName)]\n        public static extern bool FillRect(IntPtr hDC, ref RECT Rect, IntPtr Brush);\n\n        [DllImport(DllName)]\n        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPositionFlags wFlags);\n\n        [DllImport(DllName)]\n        public static extern int ShowWindow(IntPtr hWnd, int nCmdShow);\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/ScreenWrapper.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing System.Windows.Forms;\n\nnamespace Captura.Video\n{\n    class ScreenWrapper : IScreen\n    {\n        readonly Screen _screen;\n\n        ScreenWrapper(Screen Screen)\n        {\n            _screen = Screen;\n        }\n\n        public Rectangle Rectangle => _screen.Bounds;\n\n        public string DeviceName => _screen.DeviceName;\n\n        public static IEnumerable<IScreen> Enumerate() => Screen.AllScreens.Select(M => new ScreenWrapper(M));\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Webcam/CaptureWebcam.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Runtime.InteropServices;\nusing DirectShowLib;\n\n// ReSharper disable SuspiciousTypeConversion.Global\n\nnamespace Captura.Webcam\n{\n    /// <summary>\n    /// Gets the video output of a webcam or other video device.\n    /// </summary>\n    class CaptureWebcam : ISampleGrabberCB, IDisposable\n    {\n        #region Fields\n        /// <summary> \n        ///  The video capture device filter. Read-only. To use a different \n        ///  device, dispose of the current Capture instance and create a new \n        ///  instance with the desired device. \n        /// </summary>\n        readonly Filter _videoDevice;\n\n        /// <summary>\n        ///  The control that will host the preview window. \n        /// </summary>\n        readonly IntPtr _previewWindow;\n\n        /// <summary>\n        /// The Width and Height of the video feed.\n        /// </summary>\n        public Size Size => _videoInfoHeader != null ? new Size(_videoInfoHeader.BmiHeader.Width, _videoInfoHeader.BmiHeader.Height) : Size.Empty;\n\n        /// <summary>\n        /// When graphState==Rendered, have we rendered the preview stream?\n        /// </summary>\n        bool _isPreviewRendered;\n\n        /// <summary>\n        /// Do we need the preview stream rendered (VideoDevice and PreviewWindow != null)\n        /// </summary>\n        bool _wantPreviewRendered;\n\n        /// <summary>\n        /// State of the internal filter graph.\n        /// </summary>\n        GraphState _actualGraphState;\n\n        /// <summary>\n        /// DShow Filter: Graph builder.\n        /// </summary>\n        IGraphBuilder _graphBuilder;\n\n        /// <summary>\n        /// DShow Filter: building graphs for capturing video.\n        /// </summary>\n        ICaptureGraphBuilder2 _captureGraphBuilder;\n\n        /// <summary>\n        /// DShow Filter: selected video device.\n        /// </summary>\n        IBaseFilter _videoDeviceFilter;\n\n        /// <summary>\n        /// DShow Filter: Start/Stop the filter graph -> copy of graphBuilder.\n        /// </summary>\n        IMediaControl _mediaControl;\n\n        /// <summary>\n        /// DShow Filter: Control preview window -> copy of graphBuilder.\n        /// </summary>\n        IVideoWindow _videoWindow;\n\n        /// <summary>\n        /// DShow Filter: selected video compressor.\n        /// </summary>\n        IBaseFilter _videoCompressorFilter;\n\n        /// <summary>\n        /// Grabber filter interface. \n        /// </summary>\n        IBaseFilter _baseGrabFlt;\n\n        byte[] _savedArray;\n\n        ISampleGrabber _sampGrabber;\n        VideoInfoHeader _videoInfoHeader;\n        #endregion\n\n        readonly DummyForm _form;\n\n        public CaptureWebcam(Filter VideoDevice, Action OnClick, IntPtr PreviewWindow)\n        {\n            _videoDevice = VideoDevice ?? throw new ArgumentException(\"The videoDevice parameter must be set to a valid Filter.\\n\");\n\n            _form = new DummyForm();\n            _form.Show();\n\n            _form.Click += (S, E) => OnClick?.Invoke();\n\n            _previewWindow = PreviewWindow != IntPtr.Zero ? PreviewWindow : _form.Handle;\n\n            CreateGraph();\n        }\n\n        #region Public Methods\n        /// <summary>\n        /// Starts the video preview from the video source.\n        /// </summary>\n        public void StartPreview()\n        {\n            DerenderGraph();\n\n            _wantPreviewRendered = _previewWindow != IntPtr.Zero && _videoDevice != null;\n\n            RenderGraph();\n            StartPreviewIfNeeded();\n        }\n\n        /// <summary>\n        /// Stops the video previewing.\n        /// </summary>\n        public void StopPreview()\n        {\n            DerenderGraph();\n\n            _wantPreviewRendered = false;\n\n            RenderGraph();\n            StartPreviewIfNeeded();\n        }\n\n        /// <summary> Resize the preview when the PreviewWindow is resized </summary>\n        public void OnPreviewWindowResize(int X, int Y, int Width, int Height)\n        {\n            // Position video window in client rect of owner window.\n            _videoWindow?.SetWindowPosition(X, Y, Width, Height);\n        }\n\n        /// <summary>\n        /// Gets the current frame from the buffer.\n        /// </summary>\n        /// <returns>The Bitmap of the frame.</returns>\n        public IBitmapImage GetFrame(IBitmapLoader BitmapLoader)\n        {\n            if (_actualGraphState != GraphState.Rendered)\n                return null;\n\n            // Asks for the buffer size.\n            var bufferSize = 0;\n            _sampGrabber.GetCurrentBuffer(ref bufferSize, IntPtr.Zero);\n\n            if (bufferSize <= 0)\n            {\n                return null;\n            }\n\n            if (_savedArray == null || _savedArray.Length < bufferSize)\n                _savedArray = new byte[bufferSize + 64000];\n\n            // Allocs the byte array.\n            var handleObj = GCHandle.Alloc(_savedArray, GCHandleType.Pinned);\n\n            // Gets the addres of the pinned object.\n            var address = handleObj.AddrOfPinnedObject();\n\n            try\n            {\n                // Puts the buffer inside the byte array.\n                _sampGrabber.GetCurrentBuffer(ref bufferSize, address);\n\n                // Image size.\n                var width = _videoInfoHeader.BmiHeader.Width;\n                var height = _videoInfoHeader.BmiHeader.Height;\n\n                var stride = width * 4;\n                address += height * stride;\n\n                return BitmapLoader.CreateBitmapBgr32(new Size(width, height), address, -stride);\n            }\n            finally\n            {\n                handleObj.Free();\n            }\n        }\n\n        /// <summary>\n        /// Closes and cleans the video previewing.\n        /// </summary>\n        public void Dispose()\n        {\n            _wantPreviewRendered = false;\n\n            try { DestroyGraph(); }\n            catch { }\n\n            _form.Dispose();\n\n            _savedArray = null;\n        }\n        #endregion\n\n        #region Private Methods\n        /// <summary> \n        ///  Create a new filter graph and add filters (devices, compressors, misc),\n        ///  but leave the filters unconnected. Call RenderGraph()\n        ///  to connect the filters.\n        /// </summary>\n        void CreateGraph()\n        {\n            // Skip if already created\n            if (_actualGraphState < GraphState.Created)\n            {\n                // Make a new filter graph\n                _graphBuilder = (IGraphBuilder)new FilterGraph();\n\n                // Get the Capture Graph Builder\n                _captureGraphBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();\n\n                // Link the CaptureGraphBuilder to the filter graph\n                var hr = _captureGraphBuilder.SetFiltergraph(_graphBuilder);\n\n                if (hr < 0)\n                    Marshal.ThrowExceptionForHR(hr);\n\n                _sampGrabber = (ISampleGrabber)new SampleGrabber();\n\n                _baseGrabFlt = (IBaseFilter)_sampGrabber;\n\n                var media = new AMMediaType();\n\n                // Get the video device and add it to the filter graph\n                if (_videoDevice != null)\n                {\n                    _videoDeviceFilter = (IBaseFilter)Marshal.BindToMoniker(_videoDevice.MonikerString);\n\n                    hr = _graphBuilder.AddFilter(_videoDeviceFilter, \"Video Capture Device\");\n\n                    if (hr < 0)\n                        Marshal.ThrowExceptionForHR(hr);\n\n                    media.majorType = MediaType.Video;\n                    media.subType = MediaSubType.RGB32;\n                    media.formatType = FormatType.VideoInfo;\n                    media.temporalCompression = true;\n\n                    hr = _sampGrabber.SetMediaType(media);\n\n                    if (hr < 0)\n                        Marshal.ThrowExceptionForHR(hr);\n\n                    hr = _graphBuilder.AddFilter(_baseGrabFlt, \"Grabber\");\n\n                    if (hr < 0)\n                        Marshal.ThrowExceptionForHR(hr);\n                }\n\n                // Retrieve the stream control interface for the video device\n                // FindInterface will also add any required filters\n                // (WDM devices in particular may need additional upstream filters to function).\n\n                // Try looking for an interleaved media type\n                var cat = PinCategory.Capture;\n                var med = MediaType.Interleaved;\n                var iid = typeof(IAMStreamConfig).GUID;\n\n                hr = _captureGraphBuilder.FindInterface(cat, med, _videoDeviceFilter, iid, out _);\n\n                if (hr != 0)\n                {\n                    // If not found, try looking for a video media type\n                    med = MediaType.Video;\n                    _captureGraphBuilder.FindInterface(cat, med, _videoDeviceFilter, iid, out _);\n                }\n                \n                // Retreive the media control interface (for starting/stopping graph)\n                _mediaControl = (IMediaControl)_graphBuilder;\n\n                _videoInfoHeader = Marshal.PtrToStructure<VideoInfoHeader>(media.formatPtr);\n                Marshal.FreeCoTaskMem(media.formatPtr);\n                media.formatPtr = IntPtr.Zero;\n\n                hr = _sampGrabber.SetBufferSamples(true);\n\n                if (hr == 0)\n                    hr = _sampGrabber.SetOneShot(false);\n\n                if (hr == 0)\n                    hr = _sampGrabber.SetCallback(null, 0);\n\n                if (hr < 0)\n                    Marshal.ThrowExceptionForHR(hr);\n            }\n\n            // Update the state now that we are done\n            _actualGraphState = GraphState.Created;\n        }\n\n        /// <summary>\n        ///  Disconnect and remove all filters except the device\n        ///  and compressor filters. This is the opposite of\n        ///  renderGraph(). Soem properties such as FrameRate\n        ///  can only be set when the device output pins are not\n        ///  connected. \n        /// </summary>\n        void DerenderGraph()\n        {\n            // Stop the graph if it is running (ignore errors)\n            _mediaControl?.Stop();\n\n            // Free the preview window (ignore errors)\n            if (_videoWindow != null)\n            {\n                _videoWindow.put_Visible(OABool.False);\n                _videoWindow.put_Owner(IntPtr.Zero);\n                _videoWindow = null;\n            }\n\n            if ((int) _actualGraphState < (int) GraphState.Rendered)\n                return;\n\n            // Update the state\n            _actualGraphState = GraphState.Created;\n            _isPreviewRendered = false;\n\n            // Disconnect all filters downstream of the \n            // video and audio devices. If we have a compressor\n            // then disconnect it, but don't remove it\n            if (_videoDeviceFilter != null)\n                RemoveDownstream(_videoDeviceFilter);\n        }\n\n        /// <summary>\n        ///  Removes all filters downstream from a filter from the graph.\n        ///  This is called only by DerenderGraph() to remove everything\n        ///  from the graph except the devices and compressors. The parameter\n        ///  \"removeFirstFilter\" is used to keep a compressor (that should\n        ///  be immediately downstream of the device) if one is begin used.\n        /// </summary>\n        void RemoveDownstream(IBaseFilter Filter)\n        {\n            // Get a pin enumerator off the filter\n            var hr = Filter.EnumPins(out var pinEnum);\n\n            if (pinEnum == null)\n                return;\n\n            pinEnum.Reset();\n\n            if (hr != 0)\n                return;\n\n            // Loop through each pin\n            var pins = new IPin[1];\n\n            do\n            {\n                // Get the next pin\n                hr = pinEnum.Next(1, pins, IntPtr.Zero);\n\n                if (hr != 0 || pins[0] == null)\n                    continue;\n\n                // Get the pin it is connected to\n                pins[0].ConnectedTo(out var pinTo);\n\n                if (pinTo != null)\n                {\n                    // Is this an input pin?\n                    hr = pinTo.QueryPinInfo(out var info);\n\n                    if (hr == 0 && info.dir == PinDirection.Input)\n                    {\n                        // Recurse down this branch\n                        RemoveDownstream(info.filter);\n\n                        // Disconnect \n                        _graphBuilder.Disconnect(pinTo);\n                        _graphBuilder.Disconnect(pins[0]);\n\n                        // Remove this filter\n                        // but don't remove the video or audio compressors\n                        if (info.filter != _videoCompressorFilter)\n                            _graphBuilder.RemoveFilter(info.filter);\n                    }\n\n                    Marshal.ReleaseComObject(info.filter);\n                    Marshal.ReleaseComObject(pinTo);\n                }\n\n                Marshal.ReleaseComObject(pins[0]);\n            }\n            while (hr == 0);\n\n            Marshal.ReleaseComObject(pinEnum);\n        }\n\n        /// <summary>\n        ///  Connects the filters of a previously created graph \n        ///  (created by CreateGraph()). Once rendered the graph\n        ///  is ready to be used. This method may also destroy\n        ///  streams if we have streams we no longer want.\n        /// </summary>\n        void RenderGraph()\n        {\n            var didSomething = false;\n\n            // Stop the graph\n            _mediaControl?.Stop();\n\n            // Create the graph if needed (group should already be created)\n            CreateGraph();\n\n            // Derender the graph if we have a capture or preview stream\n            // that we no longer want. We can't derender the capture and \n            // preview streams seperately. \n            // Notice the second case will leave a capture stream intact\n            // even if we no longer want it. This allows the user that is\n            // not using the preview to Stop() and Start() without\n            // rerendering the graph.\n            if (!_wantPreviewRendered && _isPreviewRendered)\n                DerenderGraph();\n\n            // Render preview stream (only if necessary)\n            if (_wantPreviewRendered && !_isPreviewRendered)\n            {\n                // Render preview (video -> renderer)\n                var cat = PinCategory.Preview;\n                var med = MediaType.Video;\n                var hr = _captureGraphBuilder.RenderStream(cat, med, _videoDeviceFilter, _baseGrabFlt, null);\n                if (hr < 0) Marshal.ThrowExceptionForHR(hr);\n\n                // Get the IVideoWindow interface\n                _videoWindow = (IVideoWindow)_graphBuilder;\n\n                // Set the video window to be a child of the main window\n                hr = _videoWindow.put_Owner(_previewWindow);\n\n                _videoWindow.put_MessageDrain(_form.Handle);\n\n                if (hr < 0)\n                    Marshal.ThrowExceptionForHR(hr);\n\n                // Set video window style\n                hr = _videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings);\n\n                if (hr < 0)\n                    Marshal.ThrowExceptionForHR(hr);\n\n                // Make the video window visible, now that it is properly positioned\n                hr = _videoWindow.put_Visible(OABool.True);\n\n                if (hr < 0)\n                    Marshal.ThrowExceptionForHR(hr);\n\n                _isPreviewRendered = true;\n                didSomething = true;\n\n                var media = new AMMediaType();\n                hr = _sampGrabber.GetConnectedMediaType(media);\n\n                if (hr < 0)\n                    Marshal.ThrowExceptionForHR(hr);\n\n                if (media.formatType != FormatType.VideoInfo || media.formatPtr == IntPtr.Zero)\n                    throw new NotSupportedException(\"Unknown Grabber Media Format\");\n\n                _videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));\n\n                Marshal.FreeCoTaskMem(media.formatPtr);\n                media.formatPtr = IntPtr.Zero;\n            }\n\n            if (didSomething)\n                _actualGraphState = GraphState.Rendered;\n        }\n\n        /// <summary>\n        ///  Setup and start the preview window if the user has\n        ///  requested it (by setting PreviewWindow).\n        /// </summary>\n        void StartPreviewIfNeeded()\n        {\n            // Render preview \n            if (_wantPreviewRendered && _isPreviewRendered)\n            {\n                // Run the graph (ignore errors)\n                // We can run the entire graph becuase the capture\n                // stream should not be rendered (and that is enforced\n                // in the if statement above)\n                _mediaControl.Run();\n            }\n        }\n\n        /// <summary>\n        ///  Completely tear down a filter graph and \n        ///  release all associated resources.\n        /// </summary>\n        void DestroyGraph()\n        {\n            // Derender the graph (This will stop the graph\n            // and release preview window. It also destroys\n            // half of the graph which is unnecessary but\n            // harmless here.) (ignore errors)\n            try { DerenderGraph(); }\n            catch { }\n\n            // Update the state after derender because it\n            // depends on correct status. But we also want to\n            // update the state as early as possible in case\n            // of error.\n            _actualGraphState = GraphState.Null;\n            _isPreviewRendered = false;\n\n            // Remove filters from the graph\n            // This should be unnecessary but the Nvidia WDM\n            // video driver cannot be used by this application \n            // again unless we remove it. Ideally, we should\n            // simply enumerate all the filters in the graph\n            // and remove them. (ignore errors)\n            if (_graphBuilder != null)\n            {\n                if (_videoCompressorFilter != null)\n                    _graphBuilder.RemoveFilter(_videoCompressorFilter);\n\n                if (_videoDeviceFilter != null)\n                    _graphBuilder.RemoveFilter(_videoDeviceFilter);\n\n                // Cleanup\n                Marshal.ReleaseComObject(_graphBuilder);\n                _graphBuilder = null;\n            }\n\n            if (_captureGraphBuilder != null)\n            {\n                Marshal.ReleaseComObject(_captureGraphBuilder);\n\n                _captureGraphBuilder = null;\n            }\n\n            if (_videoDeviceFilter != null)\n            {\n                Marshal.ReleaseComObject(_videoDeviceFilter);\n\n                _videoDeviceFilter = null;\n            }\n\n            if (_videoCompressorFilter != null)\n            {\n                Marshal.ReleaseComObject(_videoCompressorFilter);\n\n                _videoCompressorFilter = null;\n            }\n\n            // These are copies of graphBuilder\n            _mediaControl = null;\n            _videoWindow = null;\n\n            // For unmanaged objects we haven't released explicitly\n            GC.Collect();\n        }\n        #endregion\n\n        #region SampleGrabber\n        int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample Sample) => 0;\n\n        int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr Buffer, int BufferLen) => 1;\n        #endregion\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Webcam/DummyForm.cs",
    "content": "﻿using System;\nusing System.Windows.Forms;\n\nnamespace Captura.Webcam\n{\n    class DummyForm : Form\n    {\n        public DummyForm()\n        {\n            Opacity = 0;\n            ShowInTaskbar = false;\n        }\n\n        protected override void WndProc(ref Message M)\n        {\n            const int msgLeftButtonDown = 513;\n\n            if (M.Msg == msgLeftButtonDown)\n            {\n                OnClick(EventArgs.Empty);\n            }\n\n            base.WndProc(ref M);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Webcam/Filter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\nusing System.Runtime.InteropServices.ComTypes;\nusing DirectShowLib;\n\nnamespace Captura.Webcam\n{\n    /// <summary>\n    ///  Represents a DirectShow filter (e.g. video capture device, compression codec).\n    /// </summary>\n    class Filter : IComparable\n    {\n        /// <summary> Human-readable name of the filter </summary>\n        public string Name { get; }\n\n        /// <summary> Unique string referencing this filter. This string can be used to recreate this filter. </summary>\n        public string MonikerString { get; }\n\n        /// <summary> Create a new filter from its moniker </summary>\n        public Filter(IMoniker Moniker)\n        {\n            Name = GetName(Moniker);\n            MonikerString = GetMonikerString(Moniker);\n        }\n\n        /// <summary> Retrieve the a moniker's display name (i.e. it's unique string) </summary>\n        static string GetMonikerString(IMoniker Moniker)\n        {\n            Moniker.GetDisplayName(null, null, out var s);\n            return s;\n        }\n\n        /// <summary> Retrieve the human-readable name of the filter </summary>\n        static string GetName(IMoniker Moniker)\n        {\n            object bagObj = null;\n\n            try\n            {\n                var bagId = typeof(IPropertyBag).GUID;\n                Moniker.BindToStorage(null, null, ref bagId, out bagObj);\n                var bag = (IPropertyBag)bagObj;\n                var hr = bag.Read(\"FriendlyName\", out var val, null);\n\n                if (hr != 0)\n                    Marshal.ThrowExceptionForHR(hr);\n\n                var ret = val as string;\n\n                if (string.IsNullOrEmpty(ret))\n                    throw new NotImplementedException(\"Device FriendlyName\");\n                return ret;\n            }\n            catch (Exception)\n            {\n                return \"\";\n            }\n            finally\n            {\n                if (bagObj != null)\n                    Marshal.ReleaseComObject(bagObj);\n            }\n        }\n\n        /// <summary>\n        ///  Compares the current instance with another object of the same type.\n        /// </summary>\n        public int CompareTo(object Obj)\n        {\n            if (Obj == null)\n                return 1;\n\n            var f = (Filter)Obj;\n\n            return string.Compare(Name, f.Name, StringComparison.Ordinal);\n        }\n\n        public static IEnumerable<Filter> VideoInputDevices\n        {\n            get\n            {\n                object comObj = null;\n                IEnumMoniker enumMon = null;\n                var mon = new IMoniker[1];\n\n                try\n                {\n                    // Get the system device enumerator\n                    comObj = new CreateDevEnum();\n                    var enumDev = (ICreateDevEnum)comObj;\n\n                    var category = FilterCategory.VideoInputDevice;\n\n                    // Create an enumerator to find filters in category\n                    var hr = enumDev.CreateClassEnumerator(category, out enumMon, 0);\n                    if (hr != 0)\n                        yield break;\n\n                    // Loop through the enumerator\n                    do\n                    {\n                        // Next filter\n                        hr = enumMon.Next(1, mon, IntPtr.Zero);\n\n                        if (hr != 0 || mon[0] == null)\n                            break;\n\n                        // Add the filter\n                        yield return new Filter(mon[0]);\n\n                        // Release resources\n                        Marshal.ReleaseComObject(mon[0]);\n                        mon[0] = null;\n                    } while (true);\n                }\n                finally\n                {\n                    if (mon[0] != null)\n                        Marshal.ReleaseComObject(mon[0]);\n\n                    mon[0] = null;\n\n                    if (enumMon != null)\n                        Marshal.ReleaseComObject(enumMon);\n\n                    if (comObj != null)\n                        Marshal.ReleaseComObject(comObj);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Webcam/GraphState.cs",
    "content": "﻿namespace Captura.Webcam\n{\n    /// <summary> \n    /// Possible states of the interal filter graph.\n    /// </summary>\n    enum GraphState\n    {\n        /// <summary>\n        /// No filter graph at all.\n        /// </summary>\n        Null,\n\n        /// <summary>\n        /// Filter graph created with device filters added.\n        /// </summary>\n        Created,\n\n        /// <summary>\n        /// Filter complete built, ready to run (possibly previewing).\n        /// </summary>\n        Rendered\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Webcam/README.md",
    "content": "# Captura.Webcam\nAdapted from [ScreenToGif](https://github.com/NickeManarin/ScreenToGif/)\n\nUses [DirectShow.NET](http://directshownet.sourceforge.net/)\n\nLicensed under [Microsoft Public License](https://github.com/NickeManarin/ScreenToGif/blob/master/LICENSE.txt)."
  },
  {
    "path": "src/Captura.Windows/Webcam/WebcamCapture.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Models;\nusing Captura.Video;\n\nnamespace Captura.Webcam\n{\n    class WebcamCapture : IWebcamCapture\n    {\n        readonly Filter _filter;\n        readonly Action _onClick;\n        CaptureWebcam _captureWebcam;\n        readonly SyncContextManager _syncContext = new SyncContextManager();\n\n        public WebcamCapture(Filter Filter, Action OnClick)\n        {\n            _filter = Filter;\n            _onClick = OnClick;\n            _captureWebcam = new CaptureWebcam(Filter, OnClick, IntPtr.Zero);\n\n            _captureWebcam.StartPreview();\n        }\n\n        public void Dispose()\n        {\n            _syncContext.Run(() =>\n            {\n                _captureWebcam.StopPreview();\n                _captureWebcam.Dispose();\n            });\n        }\n\n        public IBitmapImage Capture(IBitmapLoader BitmapLoader)\n        {\n            return _syncContext.Run(() => _captureWebcam.GetFrame(BitmapLoader));\n        }\n\n        public int Width => _captureWebcam.Size.Width;\n        public int Height => _captureWebcam.Size.Height;\n\n        IntPtr _lastWin;\n\n        public void UpdatePreview(IWindow Window, Rectangle Location)\n        {\n            _syncContext.Run(() =>\n            {\n                if (Window != null && _lastWin != Window.Handle)\n                {\n                    Dispose();\n\n                    _captureWebcam = new CaptureWebcam(_filter, _onClick, Window.Handle);\n\n                    _captureWebcam.StartPreview();\n\n                    _lastWin = Window.Handle;\n                }\n\n                _captureWebcam.OnPreviewWindowResize(Location.X, Location.Y, Location.Width, Location.Height);\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Webcam/WebcamItem.cs",
    "content": "﻿using System;\n\nnamespace Captura.Webcam\n{\n    class WebcamItem : IWebcamItem\n    {\n        public WebcamItem(Filter Cam)\n        {\n            this.Cam = Cam ?? throw new ArgumentNullException(nameof(Cam));\n            Name = Cam.Name;\n        }\n\n        public Filter Cam { get; }\n\n        public string Name { get; }\n\n        public IWebcamCapture BeginCapture(Action OnClick)\n        {\n            return new WebcamCapture(Cam, OnClick);\n        }\n\n        public override string ToString() => Name;\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/Webcam/WebcamProvider.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\n\nnamespace Captura.Webcam\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class WebcamProvider : NotifyPropertyChanged, IWebCamProvider\n    {\n        public IEnumerable<IWebcamItem> GetSources()\n        {\n            return Filter.VideoInputDevices.Select(M => new WebcamItem(M));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Captura.Windows/Window.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing Captura.Native;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Minimal representation of a Window.\n    /// </summary>\n    class Window : IWindow\n    {\n        /// <summary>\n        /// Creates a new instance of <see cref=\"Window\"/>.\n        /// </summary>\n        /// <param name=\"Handle\">The Window Handle.</param>\n        public Window(IntPtr Handle)\n        {\n            if (!User32.IsWindow(Handle))\n                throw new ArgumentException(\"Not a Window.\", nameof(Handle));\n\n            this.Handle = Handle;\n        }\n\n        public bool IsAlive => User32.IsWindow(Handle);\n\n        /// <summary>\n        /// Gets whether the Window is Visible.\n        /// </summary>\n        public bool IsVisible => User32.IsWindowVisible(Handle);\n\n        public bool IsMaximized => User32.IsZoomed(Handle);\n\n        /// <summary>\n        /// Gets the Window Handle.\n        /// </summary>\n        public IntPtr Handle { get; }\n\n        /// <summary>\n        /// Gets the Window Title.\n        /// </summary>\n        public string Title\n        {\n            get\n            {\n                var title = new StringBuilder(User32.GetWindowTextLength(Handle) + 1);\n                User32.GetWindowText(Handle, title, title.Capacity);\n                return title.ToString();\n            }\n        }\n\n        /// <summary>\n        /// Get the Window Rectangle\n        /// </summary>\n        public Rectangle Rectangle\n        {\n            get\n            {\n                var r = new RECT();\n\n                const int extendedFrameBounds = 9;\n\n                if (DwmApi.DwmGetWindowAttribute(Handle, extendedFrameBounds, ref r, Marshal.SizeOf<RECT>()) != 0)\n                {\n                    if (!User32.GetWindowRect(Handle, out r))\n                        return Rectangle.Empty;\n                }\n\n                return r.ToRectangle();\n            }\n        }\n\n        /// <summary>\n        /// Gets the Desktop Window.\n        /// </summary>\n        public static Window DesktopWindow { get; } = new Window(User32.GetDesktopWindow());\n\n        /// <summary>\n        /// Gets the Foreground Window.\n        /// </summary>\n        public static Window ForegroundWindow => new Window(User32.GetForegroundWindow());\n\n        /// <summary>\n        /// Enumerates all Windows.\n        /// </summary>\n        public static IEnumerable<Window> Enumerate()\n        {\n            var list = new List<Window>();\n\n            User32.EnumWindows((Handle, Param) =>\n            {\n                var wh = new Window(Handle);\n\n                list.Add(wh);\n\n                return true;\n            }, IntPtr.Zero);\n\n            return list;\n        }\n\n        public IEnumerable<Window> EnumerateChildren()\n        {\n            var list = new List<Window>();\n\n            User32.EnumChildWindows(Handle, (Handle, Param) =>\n            {\n                var wh = new Window(Handle);\n\n                list.Add(wh);\n\n                return true;\n            }, IntPtr.Zero);\n\n            return list;\n        }\n\n        /// <summary>\n        /// Enumerates all visible windows with a Title.\n        /// </summary>\n        public static IEnumerable<Window> EnumerateVisible()\n        {\n            foreach (var window in Enumerate().Where(W => W.IsVisible && !string.IsNullOrWhiteSpace(W.Title)))\n            {\n                var hWnd = window.Handle;\n\n                if (!User32.GetWindowLong(hWnd, GetWindowLongValue.ExStyle).HasFlag(WindowStyles.AppWindow))\n                {\n                    if (User32.GetWindow(hWnd, GetWindowEnum.Owner) != IntPtr.Zero)\n                        continue;\n\n                    if (User32.GetWindowLong(hWnd, GetWindowLongValue.ExStyle).HasFlag(WindowStyles.ToolWindow))\n                        continue;\n\n                    if (User32.GetWindowLong(hWnd, GetWindowLongValue.Style).HasFlag(WindowStyles.Child))\n                        continue;\n                }\n\n                const int dwmCloaked = 14;\n\n                // Exclude suspended Windows apps\n                DwmApi.DwmGetWindowAttribute(hWnd, dwmCloaked, out var cloaked, Marshal.SizeOf<bool>());\n\n                if (cloaked)\n                    continue;\n\n                yield return window;\n            }\n        }\n\n        /// <summary>\n        /// Returns the Widow Title.\n        /// </summary>\n        public override string ToString() => Title;\n\n        /// <summary>\n        /// Determines whether the specified object is equal to the current object.\n        /// </summary>\n        /// <returns>\n        /// true if the specified object  is equal to the current object; otherwise, false.\n        /// </returns>\n        /// <param name=\"Obj\">The object to compare with the current object. </param>\n        public override bool Equals(object Obj) => Obj is Window w && w.Handle == Handle;\n        \n        /// <summary>\n        /// Serves as the default hash function. \n        /// </summary>\n        /// <returns>\n        /// A hash code for the current object.\n        /// </returns>\n        public override int GetHashCode() => Handle.GetHashCode();\n\n        /// <summary>\n        /// Checks whether two <see cref=\"Window\"/> instances are equal.\n        /// </summary>\n        public static bool operator ==(Window W1, Window W2) => W1?.Handle == W2?.Handle;\n\n        /// <summary>\n        /// Checks whether two <see cref=\"Window\"/> instances are not equal.\n        /// </summary>\n        public static bool operator !=(Window W1, Window W2) => !(W1 == W2);\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/WindowsModule.cs",
    "content": "﻿using Captura.Audio;\nusing Captura.Models;\nusing System;\nusing Captura.Video;\nusing Captura.Webcam;\nusing Captura.Windows.Gdi;\nusing Captura.Windows.MediaFoundation;\n\nnamespace Captura.Windows\n{\n    public static class WindowsModule\n    {\n        public static void Load(IBinder Binder)\n        {\n            if (Windows8OrAbove)\n            {\n                MfManager.Startup();\n                Binder.BindAsInterfaceAndClass<IVideoWriterProvider, MfWriterProvider>();\n            }\n\n            Binder.BindSingleton<WindowsSettings>();\n            Binder.Bind<IPlatformServices, WindowsPlatformServices>();\n            Binder.Bind<IDialogService, DialogService>();\n            Binder.Bind<IClipboardService, ClipboardService>();\n            Binder.Bind<IImagingSystem, DrawingImagingSystem>();\n            Binder.Bind<IWebCamProvider, WebcamProvider>();\n\n            foreach (var audioItem in MfAudioItem.Items)\n            {\n                Binder.Bind<IAudioWriterItem>(() => audioItem);\n            }\n        }\n\n        public static void Unload()\n        {\n            if (Windows8OrAbove)\n            {\n                MfManager.Shutdown();\n            }\n        }\n\n        public static bool Windows8OrAbove\n        {\n            get\n            {\n                // All versions above Windows 8 give the same version number\n                var version = new Version(6, 2, 9200, 0);\n\n                return Environment.OSVersion.Platform == PlatformID.Win32NT &&\n                       Environment.OSVersion.Version >= version;\n            }\n        }\n\n        public static bool ShouldUseGdi\n        {\n            get\n            {\n                var settings = ServiceProvider.Get<WindowsSettings>();\n\n                return !Windows8OrAbove || settings.UseGdi;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/WindowsPlatformServices.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing System.Windows.Forms;\nusing Captura.Native;\nusing Captura.Video;\nusing Captura.Windows.DesktopDuplication;\nusing SharpDX.DXGI;\n\nnamespace Captura.Windows\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class WindowsPlatformServices : IPlatformServices\n    {\n        readonly IPreviewWindow _previewWindow;\n\n        public WindowsPlatformServices(IPreviewWindow PreviewWindow)\n        {\n            _previewWindow = PreviewWindow;\n        }\n\n        public IEnumerable<IScreen> EnumerateScreens()\n        {\n            return ScreenWrapper.Enumerate();\n        }\n\n        public IEnumerable<IWindow> EnumerateWindows()\n        {\n            return Window.EnumerateVisible();\n        }\n\n        public IEnumerable<IWindow> EnumerateAllWindows()\n        {\n            return Window\n                .Enumerate()\n                .Where(M => M.IsVisible)\n                .SelectMany(GetAllChildren);\n        }\n\n        IEnumerable<Window> GetAllChildren(Window Window)\n        {\n            var children = Window\n                .EnumerateChildren()\n                .Where(M => M.IsVisible);\n\n            foreach (var child in children)\n            {\n                foreach (var grandchild in GetAllChildren(child))\n                {\n                    yield return grandchild;\n                }\n            }\n\n            yield return Window;\n        }\n\n        public IWindow GetWindow(IntPtr Handle)\n        {\n            return new Window(Handle);\n        }\n\n        public IWindow DesktopWindow => Window.DesktopWindow;\n        public IWindow ForegroundWindow => Window.ForegroundWindow;\n\n        public Rectangle DesktopRectangle => SystemInformation.VirtualScreen;\n\n        public bool DeleteFile(string FilePath)\n        {\n            return Shell32.FileOperation(FilePath, FileOperationType.Delete, 0) == 0;\n        }\n\n        public Point CursorPosition\n        {\n            get\n            {\n                var p = new Point();\n                User32.GetCursorPos(ref p);\n                return p;\n            }\n        }\n\n        public IBitmapImage CaptureTransparent(IWindow Window, bool IncludeCursor = false)\n        {\n            return ScreenShot.CaptureTransparent(Window, IncludeCursor, this);\n        }\n\n        public IBitmapImage Capture(Rectangle Region, bool IncludeCursor = false)\n        {\n            return ScreenShot.Capture(Region, IncludeCursor);\n        }\n\n        public IImageProvider GetRegionProvider(Rectangle Region, bool IncludeCursor, Func<Point> LocationFunction = null)\n        {\n            return new RegionProvider(Region, _previewWindow, IncludeCursor, LocationFunction);\n        }\n\n        public IImageProvider GetWindowProvider(IWindow Window, bool IncludeCursor)\n        {\n            return new WindowProvider(Window, _previewWindow, IncludeCursor);\n        }\n\n        public IImageProvider GetScreenProvider(IScreen Screen, bool IncludeCursor, bool StepsMode)\n        {\n            if (!WindowsModule.ShouldUseGdi && !StepsMode)\n            {\n                var output = FindOutput(Screen);\n\n                if (output != null)\n                {\n                    return new DeskDuplImageProvider(output, IncludeCursor, _previewWindow);\n                }\n            }\n\n            return GetRegionProvider(Screen.Rectangle, IncludeCursor);\n        }\n\n        static Output1 FindOutput(IScreen Screen)\n        {\n            var outputs = new Factory1()\n                .Adapters1\n                .SelectMany(M => M.Outputs);\n\n            var match = outputs.FirstOrDefault(M =>\n            {\n                var r1 = M.Description.DesktopBounds;\n                var r2 = Screen.Rectangle;\n\n                return r1.Left == r2.Left\n                       && r1.Right == r2.Right\n                       && r1.Top == r2.Top\n                       && r1.Bottom == r2.Bottom;\n            });\n\n            return match?.QueryInterface<Output1>();\n        }\n\n        public IImageProvider GetAllScreensProvider(bool IncludeCursor, bool StepsMode)\n        {\n            if (!WindowsModule.ShouldUseGdi && !StepsMode)\n            {\n                return new DeskDuplFullScreenImageProvider(IncludeCursor, _previewWindow, this);\n            }\n\n            return GetRegionProvider(DesktopRectangle, IncludeCursor);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.Windows/WindowsSettings.cs",
    "content": "﻿namespace Captura.Windows\n{\n    public class WindowsSettings : PropertyStore\n    {\n        public bool UseGdi\n        {\n            get => Get(false);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.YouTube/Captura.YouTube.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Google.Apis.YouTube.v3\" Version=\"1.36.1.1226\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Captura.YouTube/IYouTubeApiKeys.cs",
    "content": "﻿namespace Captura.YouTube\n{\n    public interface IYouTubeApiKeys\n    {\n        string YouTubeClientId { get; }\n\n        string YouTubeClientSecret { get; }\n    }\n}"
  },
  {
    "path": "src/Captura.YouTube/YouTubePrivacyStatus.cs",
    "content": "﻿namespace Captura.YouTube\n{\n    public enum YouTubePrivacyStatus\n    {\n        Public,\n        Unlisted,\n        Private\n    }\n}"
  },
  {
    "path": "src/Captura.YouTube/YouTubeUploadRequest.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Google.Apis.Upload;\nusing Google.Apis.YouTube.v3;\nusing VideoYT = Google.Apis.YouTube.v3.Data.Video;\n\nnamespace Captura.YouTube\n{\n    public class YouTubeUploadRequest : IDisposable\n    {\n        readonly VideosResource.InsertMediaUpload _videoInsertRequest;\n        readonly Stream _dataStream;\n\n        internal YouTubeUploadRequest(string FileName,\n            YouTubeService YouTubeService,\n            VideoYT Video)\n        {\n            _dataStream = new FileStream(FileName, FileMode.Open);\n            _videoInsertRequest = YouTubeService.Videos.Insert(Video, \"snippet,status\", _dataStream, \"video/*\");\n\n            _videoInsertRequest.ProgressChanged += VideosInsertRequest_ProgressChanged;\n            _videoInsertRequest.ResponseReceived += VideosInsertRequest_ResponseReceived;\n        }\n\n        void VideosInsertRequest_ProgressChanged(IUploadProgress Progress)\n        {\n            BytesSent?.Invoke(Progress.BytesSent);\n        }\n\n        void VideosInsertRequest_ResponseReceived(VideoYT Video)\n        {\n            Uploaded?.Invoke($\"https://youtube.com/watch?v={Video.Id}\");\n        }\n\n        public async Task<IUploadProgress> Upload(CancellationToken CancellationToken)\n        {\n            return await _videoInsertRequest.UploadAsync(CancellationToken);\n        }\n\n        public async Task<IUploadProgress> Resume(CancellationToken CancellationToken)\n        {\n            return await _videoInsertRequest.ResumeAsync(CancellationToken);\n        }\n\n        public event Action<long> BytesSent;\n\n        public event Action<string> Uploaded;\n\n        public void Dispose()\n        {\n            _dataStream.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.YouTube/YouTubeUploader.cs",
    "content": "﻿using System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Google.Apis.Auth.OAuth2;\nusing Google.Apis.Services;\nusing Google.Apis.YouTube.v3;\nusing Google.Apis.YouTube.v3.Data;\n\nnamespace Captura.YouTube\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class YouTubeUploader\n    {\n        readonly IYouTubeApiKeys _apiKeys;\n        readonly ProxySettings _proxySettings;\n\n        YouTubeService _youtubeService;\n\n        public YouTubeUploader(IYouTubeApiKeys ApiKeys,\n            ProxySettings ProxySettings)\n        {\n            _apiKeys = ApiKeys;\n            _proxySettings = ProxySettings;\n        }\n\n        static string GetPrivacyStatus(YouTubePrivacyStatus PrivacyStatus)\n        {\n            return PrivacyStatus.ToString().ToLower();\n        }\n\n        public async Task<YouTubeUploadRequest> CreateUploadRequest(string FileName,\n            string Title,\n            string Description,\n            string[] Tags = null,\n            YouTubePrivacyStatus PrivacyStatus = YouTubePrivacyStatus.Unlisted)\n        {\n            if (_youtubeService == null)\n                await Init();\n\n            var video = new Google.Apis.YouTube.v3.Data.Video\n            {\n                Snippet = new VideoSnippet\n                {\n                    Title = Title,\n                    Description = Description,\n                    Tags = Tags ?? new string[0],\n                    CategoryId = \"22\"\n                },\n                Status = new VideoStatus { PrivacyStatus = GetPrivacyStatus(PrivacyStatus) }\n            };\n\n            return new YouTubeUploadRequest(FileName, _youtubeService, video);\n        }\n\n        async Task Init()\n        {\n            WebRequest.DefaultWebProxy = _proxySettings.GetWebProxy();\n\n            var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync\n            (\n                new ClientSecrets\n                {\n                    ClientId = _apiKeys.YouTubeClientId,\n                    ClientSecret = _apiKeys.YouTubeClientSecret\n                },\n                // This OAuth 2.0 access scope allows an application to upload files to the\n                // authenticated user's YouTube channel, but doesn't allow other types of access.\n                new[] { YouTubeService.Scope.YoutubeUpload },\n                \"user\",\n                CancellationToken.None\n            );\n\n            _youtubeService = new YouTubeService(new BaseClientService.Initializer\n            {\n                HttpClientInitializer = credential,\n                ApplicationName = nameof(Captura)\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Captura.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.28729.10\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura\", \"Captura\\Captura.csproj\", \"{0B496E01-F328-4969-832C-C75977B4F4E6}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Screna\", \"Screna\\Screna.csproj\", \"{23CB9ADB-BA9F-4618-BD0C-589A00A532E5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.Core\", \"Captura.Core\\Captura.Core.csproj\", \"{F8568B22-8AC6-49C5-92DF-E1C359FF1FAB}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.Console\", \"Captura.Console\\Captura.Console.csproj\", \"{CC710D4D-DFE8-4B31-BD7E-59AD80737E13}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Tests\", \"Tests\\Tests.csproj\", \"{AF998FD2-10BB-4CB2-802C-B44879776544}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.Base\", \"Captura.Base\\Captura.Base.csproj\", \"{388D8B28-E629-4684-8537-8D78719B69E5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.SharpAvi\", \"Captura.SharpAvi\\Captura.SharpAvi.csproj\", \"{BB8FF9F8-EC60-4A4A-A3F0-D9FBFB585D86}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.MouseKeyHook\", \"Captura.MouseKeyHook\\Captura.MouseKeyHook.csproj\", \"{6CC6E9C8-9A94-4FB0-8396-47E2ECBD8300}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.FFmpeg\", \"Captura.FFmpeg\\Captura.FFmpeg.csproj\", \"{4E1E8F5B-6A19-48CE-9C1F-B46A0622B32C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.Loc\", \"Captura.Loc\\Captura.Loc.csproj\", \"{1E4BE8D4-A84F-4389-ACD9-277F1CB5F097}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.Hotkeys\", \"Captura.Hotkeys\\Captura.Hotkeys.csproj\", \"{A9BAFF4D-03E1-4E6A-9075-C50874C04CC7}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.Fakes\", \"Captura.Fakes\\Captura.Fakes.csproj\", \"{0BB58B16-1A6C-4256-AEC2-3EA64541B663}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.NAudio\", \"Captura.NAudio\\Captura.NAudio.csproj\", \"{76BC6324-E205-41DB-B60A-128D9FD66624}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.Imgur\", \"Captura.Imgur\\Captura.Imgur.csproj\", \"{885A212B-2642-40F8-B4CF-12F791D79D25}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.ViewCore\", \"Captura.ViewCore\\Captura.ViewCore.csproj\", \"{AD000798-A5C9-4195-A0C7-55DC80EE8C5F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.YouTube\", \"Captura.YouTube\\Captura.YouTube.csproj\", \"{224E699E-2B95-4194-BE79-4931815D8F21}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.Windows\", \"Captura.Windows\\Captura.Windows.csproj\", \"{5B10DDF4-246B-47D0-82BF-95BF3256946E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Captura.Audio\", \"Captura.Audio\\Captura.Audio.csproj\", \"{D29DE716-EDDF-4CFB-8430-D07CCACB0921}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Audio\", \"Audio\", \"{E645F466-C7D6-469A-B4CC-B0917703318C}\"\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{0B496E01-F328-4969-832C-C75977B4F4E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0B496E01-F328-4969-832C-C75977B4F4E6}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0B496E01-F328-4969-832C-C75977B4F4E6}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0B496E01-F328-4969-832C-C75977B4F4E6}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{23CB9ADB-BA9F-4618-BD0C-589A00A532E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{23CB9ADB-BA9F-4618-BD0C-589A00A532E5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{23CB9ADB-BA9F-4618-BD0C-589A00A532E5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{23CB9ADB-BA9F-4618-BD0C-589A00A532E5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F8568B22-8AC6-49C5-92DF-E1C359FF1FAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F8568B22-8AC6-49C5-92DF-E1C359FF1FAB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F8568B22-8AC6-49C5-92DF-E1C359FF1FAB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F8568B22-8AC6-49C5-92DF-E1C359FF1FAB}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{CC710D4D-DFE8-4B31-BD7E-59AD80737E13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CC710D4D-DFE8-4B31-BD7E-59AD80737E13}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CC710D4D-DFE8-4B31-BD7E-59AD80737E13}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CC710D4D-DFE8-4B31-BD7E-59AD80737E13}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{AF998FD2-10BB-4CB2-802C-B44879776544}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AF998FD2-10BB-4CB2-802C-B44879776544}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AF998FD2-10BB-4CB2-802C-B44879776544}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AF998FD2-10BB-4CB2-802C-B44879776544}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{388D8B28-E629-4684-8537-8D78719B69E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{388D8B28-E629-4684-8537-8D78719B69E5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{388D8B28-E629-4684-8537-8D78719B69E5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{388D8B28-E629-4684-8537-8D78719B69E5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{BB8FF9F8-EC60-4A4A-A3F0-D9FBFB585D86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BB8FF9F8-EC60-4A4A-A3F0-D9FBFB585D86}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BB8FF9F8-EC60-4A4A-A3F0-D9FBFB585D86}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BB8FF9F8-EC60-4A4A-A3F0-D9FBFB585D86}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6CC6E9C8-9A94-4FB0-8396-47E2ECBD8300}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6CC6E9C8-9A94-4FB0-8396-47E2ECBD8300}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6CC6E9C8-9A94-4FB0-8396-47E2ECBD8300}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6CC6E9C8-9A94-4FB0-8396-47E2ECBD8300}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{4E1E8F5B-6A19-48CE-9C1F-B46A0622B32C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4E1E8F5B-6A19-48CE-9C1F-B46A0622B32C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4E1E8F5B-6A19-48CE-9C1F-B46A0622B32C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4E1E8F5B-6A19-48CE-9C1F-B46A0622B32C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1E4BE8D4-A84F-4389-ACD9-277F1CB5F097}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1E4BE8D4-A84F-4389-ACD9-277F1CB5F097}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1E4BE8D4-A84F-4389-ACD9-277F1CB5F097}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1E4BE8D4-A84F-4389-ACD9-277F1CB5F097}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A9BAFF4D-03E1-4E6A-9075-C50874C04CC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A9BAFF4D-03E1-4E6A-9075-C50874C04CC7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A9BAFF4D-03E1-4E6A-9075-C50874C04CC7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A9BAFF4D-03E1-4E6A-9075-C50874C04CC7}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{0BB58B16-1A6C-4256-AEC2-3EA64541B663}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0BB58B16-1A6C-4256-AEC2-3EA64541B663}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0BB58B16-1A6C-4256-AEC2-3EA64541B663}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0BB58B16-1A6C-4256-AEC2-3EA64541B663}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{76BC6324-E205-41DB-B60A-128D9FD66624}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{76BC6324-E205-41DB-B60A-128D9FD66624}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{76BC6324-E205-41DB-B60A-128D9FD66624}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{76BC6324-E205-41DB-B60A-128D9FD66624}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{885A212B-2642-40F8-B4CF-12F791D79D25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{885A212B-2642-40F8-B4CF-12F791D79D25}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{885A212B-2642-40F8-B4CF-12F791D79D25}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{885A212B-2642-40F8-B4CF-12F791D79D25}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{AD000798-A5C9-4195-A0C7-55DC80EE8C5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AD000798-A5C9-4195-A0C7-55DC80EE8C5F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AD000798-A5C9-4195-A0C7-55DC80EE8C5F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AD000798-A5C9-4195-A0C7-55DC80EE8C5F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{224E699E-2B95-4194-BE79-4931815D8F21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{224E699E-2B95-4194-BE79-4931815D8F21}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{224E699E-2B95-4194-BE79-4931815D8F21}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{224E699E-2B95-4194-BE79-4931815D8F21}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5B10DDF4-246B-47D0-82BF-95BF3256946E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5B10DDF4-246B-47D0-82BF-95BF3256946E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5B10DDF4-246B-47D0-82BF-95BF3256946E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5B10DDF4-246B-47D0-82BF-95BF3256946E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{D29DE716-EDDF-4CFB-8430-D07CCACB0921}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D29DE716-EDDF-4CFB-8430-D07CCACB0921}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D29DE716-EDDF-4CFB-8430-D07CCACB0921}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D29DE716-EDDF-4CFB-8430-D07CCACB0921}.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{76BC6324-E205-41DB-B60A-128D9FD66624} = {E645F466-C7D6-469A-B4CC-B0917703318C}\n\t\t{D29DE716-EDDF-4CFB-8430-D07CCACB0921} = {E645F466-C7D6-469A-B4CC-B0917703318C}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {7740D998-67E7-4F55-8FB1-72606E480904}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "src/Directory.Build.props",
    "content": "<Project>\n <PropertyGroup>\n   <LangVersion>8</LangVersion>\n </PropertyGroup>\n</Project>"
  },
  {
    "path": "src/PostBuild.targets",
    "content": "<Project>\n  <PropertyGroup>\n    <RootDir>$(MSBuildThisFileDirectory)/..</RootDir>\n    <DoMoveLibs>False</DoMoveLibs>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"$(Configuration) != 'Debug'\">\n    <DoMoveLibs>True</DoMoveLibs>\n    <LibFolderName>lib/</LibFolderName>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <!-- Copy License files -->\n    <Content Include=\"$(RootDir)/licenses/*.txt\">\n      <Visible>False</Visible>\n      <Link>licenses/%(Filename)%(Extension)</Link>\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </Content>\n\n    <Content Include=\"$(MSBuildThisFileDirectory)/Captura.Loc/Languages/*.json\">\n      <Visible>False</Visible>\n      <Link>Languages/%(Filename)%(Extension)</Link>\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </Content>\n  </ItemGroup>\n\n  <!-- Move Libraries to lib folder -->\n  <Target Name=\"MoveLibs\" AfterTargets=\"Build\" Condition=\"$(DoMoveLibs)\">\n    <PropertyGroup>\n      <CopyDestionationPath>$(OutputPath)/$(LibFolderName)</CopyDestionationPath>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <LibFiles Include=\"$(OutputPath)*.dll\" />\n      <PdbFiles Include=\"$(OutputPath)*.pdb\" />\n      <XmlDocFiles Include=\"$(OutputPath)*.xml\" />\n    </ItemGroup>\n\n    <Message Text=\"Moving Libraries to lib folder\" Importance=\"High\" />\n\n    <Move SourceFiles=\"@(LibFiles)\" \n          DestinationFolder=\"$(CopyDestionationPath)\" />\n\n    <Delete Files=\"@(PdbFiles)\" />\n    <Delete Files=\"@(XmlDocFiles)\" />\n  </Target>\n</Project>"
  },
  {
    "path": "src/Screna/AudioFileWriter.cs",
    "content": "﻿using System;\nusing System.IO;\nusing static System.Text.Encoding;\n\nnamespace Captura.Audio\n{\n    /// <summary>\n    /// Writes an Audio file.\n    /// </summary>\n    public class AudioFileWriter : IAudioFileWriter\n    {\n        readonly object _syncLock = new object();\n        readonly BinaryWriter _writer;\n        readonly WaveFormat _format;\n\n        readonly long _dataSizePos, _factSampleCountPos;\n\n        readonly bool _riff;\n\n        /// <summary>\n        /// Creates a new instance of <see cref=\"AudioFileWriter\"/>.\n        /// </summary>\n        public AudioFileWriter(Stream OutStream, WaveFormat Format, bool Riff = true)\n        {\n            if (OutStream == null)\n                throw new ArgumentNullException(nameof(OutStream));\n\n            _format = Format ?? throw new ArgumentNullException(nameof(Format));\n            _riff = Riff;\n\n            _writer = new BinaryWriter(OutStream, UTF8);\n\n            if (Riff)\n            {\n                _writer.Write(UTF8.GetBytes(\"RIFF\"));\n                _writer.Write(0); // placeholder\n                _writer.Write(UTF8.GetBytes(\"WAVE\"));\n\n                _writer.Write(UTF8.GetBytes(\"fmt \"));\n\n                _writer.Write(18 + Format.ExtraSize); // wave format length\n            }\n\n            Format.Serialize(_writer);\n\n            if (!Riff)\n                return;\n\n            // CreateFactChunk\n            if (HasFactChunk)\n            {\n                _writer.Write(UTF8.GetBytes(\"fact\"));\n                _writer.Write(4);\n                _factSampleCountPos = OutStream.Position;\n                _writer.Write(0); // number of samples\n            }\n\n            // WriteDataChunkHeader\n            _writer.Write(UTF8.GetBytes(\"data\"));\n            _dataSizePos = OutStream.Position;\n            _writer.Write(0); // placeholder\n        }\n\n        /// <summary>\n        /// Creates a new instance of <see cref=\"AudioFileWriter\"/>.\n        /// </summary>\n        public AudioFileWriter(string FileName, WaveFormat Format, bool Riff = true)\n            : this(new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read), Format, Riff) { }\n        \n        bool HasFactChunk => _format.Encoding != WaveFormatEncoding.Pcm && _format.BitsPerSample != 0;\n        \n        /// <summary>\n        /// Number of bytes of audio in the data chunk\n        /// </summary>\n        public long Length { get; private set; }\n\n        /// <summary>\n        /// Writes to file.\n        /// </summary>\n        public void Write(byte[] Data, int Offset, int Count)\n        {\n            lock (_syncLock)\n            {\n                if (_riff && _writer.BaseStream.Length + Count > uint.MaxValue)\n                    throw new ArgumentException(\"WAV file too large\", nameof(Count));\n                \n                _writer.Write(Data, Offset, Count);\n                Length += Count;\n            }\n        }\n\n        /// <summary>\n        /// Writes all buffered data to file.\n        /// </summary>\n        public void Flush()\n        {\n            lock (_syncLock)\n            {\n                _writer.Flush();\n                \n                if (!_riff)\n                    return;\n\n                var pos = _writer.BaseStream.Position;\n                UpdateHeader();\n                _writer.BaseStream.Position = pos;\n            }\n        }\n        \n        /// <summary>\n        /// Updates the header with file size information\n        /// </summary>\n        void UpdateHeader()\n        {\n            // UpdateRiffChunk\n            _writer.Seek(4, SeekOrigin.Begin);\n            _writer.Write((uint)(_writer.BaseStream.Length - 8));\n\n            // UpdateFactChunk\n            if (HasFactChunk)\n            {\n                var bitsPerSample = _format.BitsPerSample * _format.Channels;\n                if (bitsPerSample != 0)\n                {\n                    _writer.Seek((int)_factSampleCountPos, SeekOrigin.Begin);\n\n                    _writer.Write((int)(Length * 8 / bitsPerSample));\n                }\n            }\n\n            // UpdateDataChunk\n            _writer.Seek((int)_dataSizePos, SeekOrigin.Begin);\n            _writer.Write((uint)Length);\n        }\n\n        /// <summary>\n        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\n        /// </summary>\n        public void Dispose()\n        {\n            using (_writer)\n                Flush();\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/AudioRecorder.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Captura.Audio\n{\n    public class AudioRecorder : IRecorder\n    {\n        IAudioFileWriter _audioWriter;\n        IAudioProvider _audioProvider;\n\n        readonly ManualResetEvent _continueEvent = new ManualResetEvent(false),\n            _stopEvent = new ManualResetEvent(false);\n\n        byte[] _buffer;\n        const int ReadInterval = 200;\n        readonly Task _loopTask;\n\n        public AudioRecorder(IAudioFileWriter AudioWriter, IAudioProvider AudioProvider)\n        {\n            _audioWriter = AudioWriter ?? throw new ArgumentNullException(nameof(AudioWriter));\n            _audioProvider = AudioProvider ?? throw new ArgumentNullException(nameof(AudioProvider));\n\n            var wf = _audioProvider.WaveFormat;\n\n            var bufferSize = (int)\n            (\n                (ReadInterval / 1000.0)\n                * wf.SampleRate\n                * wf.Channels\n                * (wf.BitsPerSample / 8.0)\n            );\n\n            _buffer = new byte[bufferSize];\n\n            _loopTask = Task.Factory.StartNew(Loop, TaskCreationOptions.LongRunning);\n        }\n\n        public void Dispose()\n        {\n            _continueEvent.Set();\n            _stopEvent.Set();\n\n            _loopTask.Wait();\n\n            _buffer = null;\n\n            _audioWriter.Dispose();\n            _audioWriter = null;\n\n            _audioProvider.Dispose();\n            _audioProvider = null;\n        }\n\n        public void Start()\n        {\n            _audioProvider.Start();\n\n            _continueEvent.Set();\n        }\n\n        public void Stop()\n        {\n            _continueEvent.Reset();\n\n            _audioProvider.Stop();\n        }\n\n        void Loop()\n        {\n            bool CanContinue()\n            {\n                try\n                {\n                    return _continueEvent.WaitOne() && !_stopEvent.WaitOne(0);\n                }\n                catch (ObjectDisposedException)\n                {\n                    return false;\n                }\n            }\n\n            while (CanContinue())\n            {\n                var read = _audioProvider.Read(_buffer, 0, _buffer.Length);\n\n                _audioWriter.Write(_buffer, 0, read);\n\n                Thread.Sleep(ReadInterval);\n            }\n        }\n\n        public event Action<Exception> ErrorOccurred;\n    }\n}"
  },
  {
    "path": "src/Screna/Extensions.cs",
    "content": "﻿using System.Drawing;\nusing System.Linq;\nusing System.Text.RegularExpressions;\n\nnamespace Captura\n{\n    /// <summary>\n    /// Collection of utility methods.\n    /// </summary>\n    public static class Extensions\n    {\n        public static Rectangle Even(this Rectangle Rect)\n        {\n            if (Rect.Width % 2 == 1)\n                --Rect.Width;\n\n            if (Rect.Height % 2 == 1)\n                --Rect.Height;\n\n            return Rect;\n        }\n\n        const string RectRegex = @\"-?\\d+,-?\\d+,\\d+,\\d+\";\n\n        public static Rectangle? ConvertToRectangle(this string Value)\n        {\n            if (Regex.IsMatch(Value, RectRegex))\n            {\n                var x = Value.Split(',')\n                    .Select(int.Parse)\n                    .ToArray();\n\n                return new Rectangle(x[0], x[1], x[2], x[3]);\n            }\n\n            return null;\n        }\n\n        public static string ConvertToString(this Rectangle Rect)\n        {\n            var x = new[] { Rect.X, Rect.Y, Rect.Width, Rect.Height };\n\n            return string.Join(\",\", x.Select(M => M.ToString()));\n        }\n\n        public static void WriteToClipboard(this string S)\n        {\n            if (S == null)\n                return;\n\n            var clipboard = ServiceProvider.Get<IClipboardService>();\n\n            clipboard.SetText(S);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/ImageProviders/AroundMouseImageProvider.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    public class AroundMouseImageProvider : IImageProvider\n    {\n        readonly IPlatformServices _platformServices;\n        readonly IImageProvider _regionProvider;\n        Rectangle _regionAroundMouse;\n        readonly int _margin;\n\n        public AroundMouseImageProvider(int Width,\n            int Height,\n            int Margin,\n            IPlatformServices PlatformServices,\n            bool IncludeCursor)\n        {\n            _platformServices = PlatformServices;\n            _margin = Margin;\n\n            this.Width = Width;\n            this.Height = Height;\n\n            _regionAroundMouse = new Rectangle(0, 0, Width, Height);\n\n            PointTransform = P => new Point(P.X - _regionAroundMouse.X, P.Y - _regionAroundMouse.Y);            \n\n            _regionProvider = PlatformServices.GetRegionProvider(_regionAroundMouse,\n                IncludeCursor,\n                () => _regionAroundMouse.Location);\n        }\n\n        public int Height { get; }\n\n        public int Width { get; }\n\n        public Func<Point, Point> PointTransform { get; }\n\n        void ShiftRegion(Point CursorPos, Rectangle OffsetRegion)\n        {\n            if (CursorPos.X < OffsetRegion.X)\n            {\n                _regionAroundMouse.X = CursorPos.X - _margin;\n            }\n\n            if (CursorPos.Y < OffsetRegion.Y)\n            {\n                _regionAroundMouse.Y = CursorPos.Y - _margin;\n            }\n\n            if (CursorPos.X > OffsetRegion.Right)\n            {\n                _regionAroundMouse.X = CursorPos.X - OffsetRegion.Width - _margin;\n            }\n\n            if (CursorPos.Y > OffsetRegion.Bottom)\n            {\n                _regionAroundMouse.Y = CursorPos.Y - OffsetRegion.Height - _margin;\n            }\n        }\n\n        void CheckBounds(Rectangle ScreenBounds)\n        {\n            if (_regionAroundMouse.Right > ScreenBounds.Right)\n            {\n                _regionAroundMouse.X = ScreenBounds.Right - Width;\n            }\n\n            if (_regionAroundMouse.Bottom > ScreenBounds.Bottom)\n            {\n                _regionAroundMouse.Y = ScreenBounds.Bottom - Height;\n            }\n\n            if (_regionAroundMouse.X < ScreenBounds.X)\n            {\n                _regionAroundMouse.X = ScreenBounds.X;\n            }\n\n            if (_regionAroundMouse.Y < ScreenBounds.Y)\n            {\n                _regionAroundMouse.Y = ScreenBounds.Y;\n            }\n        }\n\n        public IEditableFrame Capture()\n        {\n            var cursorPos = _platformServices.CursorPosition;\n\n            var offsetRegion = new Rectangle(_regionAroundMouse.Location, _regionAroundMouse.Size);\n            offsetRegion.Inflate(-_margin, -_margin);\n\n            if (!offsetRegion.Contains(cursorPos))\n            {\n                ShiftRegion(cursorPos, offsetRegion);\n\n                var screenBounds = _platformServices.DesktopRectangle;\n                CheckBounds(screenBounds);\n            }\n\n            return _regionProvider.Capture();\n        }\n\n        public void Dispose()\n        {\n            _regionProvider.Dispose();\n        }\n\n        public IBitmapFrame DummyFrame => _regionProvider.DummyFrame;\n    }\n}\n"
  },
  {
    "path": "src/Screna/ImageProviders/OverlayedImageProvider.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Applies Overlays on an <see cref=\"IImageProvider\"/>.\n    /// </summary>\n    public class OverlayedImageProvider : IImageProvider\n    {\n        IOverlay[] _overlays;\n        IImageProvider _imageProvider;\n        \n        /// <summary>\n        /// Creates a new instance of <see cref=\"OverlayedImageProvider\"/>.\n        /// </summary>\n        /// <param name=\"ImageProvider\">The <see cref=\"IImageProvider\"/> to apply the Overlays on.</param>\n        /// <param name=\"Overlays\">Array of <see cref=\"IOverlay\"/>(s) to apply.</param>\n        public OverlayedImageProvider(IImageProvider ImageProvider, params IOverlay[] Overlays)\n        {\n            _imageProvider = ImageProvider ?? throw new ArgumentNullException(nameof(ImageProvider));\n            _overlays = Overlays ?? throw new ArgumentNullException(nameof(Overlays));\n\n            Width = ImageProvider.Width;\n            Height = ImageProvider.Height;\n        }\n\n        /// <inheritdoc />\n        public IEditableFrame Capture()\n        {\n            var bmp = _imageProvider.Capture();\n            \n            // Overlays should have already been drawn on previous frame\n            if (bmp is RepeatFrame)\n            {\n                return bmp;\n            }\n\n            if (_overlays != null)\n            {\n                foreach (var overlay in _overlays)\n                    overlay?.Draw(bmp, _imageProvider.PointTransform);\n            }\n            \n            return bmp;\n        }\n        \n        /// <inheritdoc />\n        public int Height { get; }\n\n        /// <inheritdoc />\n        public int Width { get; }\n\n        public Func<Point, Point> PointTransform => _imageProvider.PointTransform;\n\n        /// <inheritdoc />\n        public void Dispose()\n        {\n            _imageProvider.Dispose();\n\n            foreach (var overlay in _overlays)\n                overlay?.Dispose();\n\n            _imageProvider = null;\n            _overlays = null;\n        }\n\n        public IBitmapFrame DummyFrame => _imageProvider.DummyFrame;\n    }\n}\n"
  },
  {
    "path": "src/Screna/MultiDisposeFrame.cs",
    "content": "﻿using System;\nusing Captura.Models;\n\nnamespace Captura.Video\n{\n    public class MultiDisposeFrame : IBitmapFrame, IFrameWrapper\n    {\n        int _count;\n\n        public IBitmapFrame Frame { get; }\n\n        readonly object _syncLock = new object();\n\n        public MultiDisposeFrame(IBitmapFrame Frame, int Count)\n        {\n            if (this.Frame is RepeatFrame)\n            {\n                throw new NotSupportedException();\n            }\n\n            if (Count < 2)\n            {\n                throw new ArgumentException(\"Count should be atleast 2\", nameof(Count));\n            }\n\n            this.Frame = Frame ?? throw new ArgumentNullException(nameof(Frame));\n            _count = Count;\n        }\n\n        public void Dispose()\n        {\n            lock (_syncLock)\n            {\n                --_count;\n\n                if (_count == 0)\n                {\n                    Frame.Dispose();\n                }\n            }\n        }\n\n        public int Width => Frame.Width;\n        public int Height => Frame.Height;\n\n        public TimeSpan Timestamp => Frame.Timestamp;\n\n        public void CopyTo(byte[] Buffer)\n        {\n            Frame.CopyTo(Buffer);\n        }\n\n        public void CopyTo(IntPtr Buffer)\n        {\n            Frame.CopyTo(Buffer);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/MultiRecorder.cs",
    "content": "﻿using System;\n\nnamespace Captura.Video\n{\n    public class MultiRecorder : IRecorder\n    {\n        IRecorder[] _recorders;\n\n        public MultiRecorder(params IRecorder[] Recorders)\n        {\n            if (Recorders == null || Recorders.Length < 2)\n            {\n                throw new ArgumentException(\"Atleast two recorders required.\", nameof(Recorders));\n            }\n\n            _recorders = Recorders;\n\n            foreach (var recorder in Recorders)\n            {\n                recorder.ErrorOccurred += RaiseError;\n            }\n        }\n\n        void RaiseError(Exception E) => ErrorOccurred?.Invoke(E);\n\n        public void Dispose()\n        {\n            foreach (var recorder in _recorders)\n            {\n                recorder.Dispose();\n                recorder.ErrorOccurred -= RaiseError;\n            }\n\n            _recorders = null;\n        }\n\n        public void Start()\n        {\n            foreach (var recorder in _recorders)\n            {\n                recorder.Start();\n            }\n        }\n\n        public void Stop()\n        {\n            foreach (var recorder in _recorders)\n            {\n                recorder.Stop();\n            }\n        }\n\n        public event Action<Exception> ErrorOccurred;\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/CensorOverlay.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    public class CensorOverlay : IOverlay\n    {\n        readonly IEnumerable<CensorOverlaySettings> _overlaySettings;\n\n        public CensorOverlay(IEnumerable<CensorOverlaySettings> OverlaySettings)\n        {\n            _overlaySettings = OverlaySettings;\n        }\n\n        public void Dispose() { }\n\n        static float GetLeft(CensorOverlaySettings OverlaySettings, float FullWidth)\n        {\n            var x = OverlaySettings.X;\n\n            switch (OverlaySettings.HorizontalAlignment)\n            {\n                case Alignment.Start:\n                    return x;\n\n                case Alignment.End:\n                    return FullWidth - x - OverlaySettings.Width;\n\n                case Alignment.Center:\n                    return FullWidth / 2 + x - OverlaySettings.Width / 2f;\n\n                default:\n                    return 0;\n            }\n        }\n\n        static float GetTop(CensorOverlaySettings OverlaySettings, float FullHeight)\n        {\n            var y = OverlaySettings.Y;\n\n            switch (OverlaySettings.VerticalAlignment)\n            {\n                case Alignment.Start:\n                    return y;\n\n                case Alignment.End:\n                    return FullHeight - y - OverlaySettings.Height;\n\n                case Alignment.Center:\n                    return FullHeight / 2 + y - OverlaySettings.Height / 2f;\n\n                default:\n                    return 0;\n            }\n        }\n\n        public void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null)\n        {\n            foreach (var overlaySetting in _overlaySettings)\n            {\n                if (!overlaySetting.Display)\n                    continue;\n\n                Editor.FillRectangle(Color.Black,\n                    new RectangleF(\n                        GetLeft(overlaySetting, Editor.Width),\n                        GetTop(overlaySetting, Editor.Height),\n                        overlaySetting.Width,\n                        overlaySetting.Height));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/CustomImageOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    public class CustomImageOverlay : ImageOverlay\n    {\n        IBitmapImage _bmp;\n        readonly CustomImageOverlaySettings _settings;\n\n        public CustomImageOverlay(CustomImageOverlaySettings ImageOverlaySettings)\n            : base(false)\n        {\n            _settings = ImageOverlaySettings;\n        }\n\n        public override void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null)\n        {\n            var img = GetImage(Editor);\n\n            var size = new Size(img.Width, img.Height);\n\n            if (_settings.Resize)\n                size = new Size(_settings.ResizeWidth, _settings.ResizeHeight);\n\n            var pos = GetPosition(new SizeF(Editor.Width, Editor.Height), size);\n\n            Draw(Editor, img, pos, size, _settings.Opacity);\n        }\n\n        public override void Dispose()\n        {\n            _bmp?.Dispose();\n        }\n\n        PointF GetPosition(SizeF Bounds, Size ImageSize)\n        {\n            var point = new PointF(_settings.X, _settings.Y);\n\n            switch (_settings.HorizontalAlignment)\n            {\n                case Alignment.Center:\n                    point.X = Bounds.Width / 2 - ImageSize.Width / 2f + point.X;\n                    break;\n\n                case Alignment.End:\n                    point.X = Bounds.Width - ImageSize.Width - point.X;\n                    break;\n            }\n\n            switch (_settings.VerticalAlignment)\n            {\n                case Alignment.Center:\n                    point.Y = Bounds.Height / 2 - ImageSize.Height / 2f + point.Y;\n                    break;\n\n                case Alignment.End:\n                    point.Y = Bounds.Height - ImageSize.Height - point.Y;\n                    break;\n            }\n\n            return point;\n        }\n\n        IBitmapImage GetImage(IEditableFrame Editor)\n        {\n            return _bmp ??= Editor.LoadBitmap(_settings.Source);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/CustomOverlay.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class CustomOverlay : TextOverlay\n    {\n        readonly CustomOverlaySettings _overlaySettings;\n        \n        public CustomOverlay(CustomOverlaySettings OverlaySettings) : base(OverlaySettings)\n        {\n            _overlaySettings = OverlaySettings;\n        }\n\n        protected override string GetText() => _overlaySettings.Text;\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/ElapsedOverlay.cs",
    "content": "﻿using System;\n\nnamespace Captura.Video\n{\n    public class ElapsedOverlay : TextOverlay\n    {\n        readonly Func<TimeSpan> _elapsed;\n\n        public ElapsedOverlay(TextOverlaySettings OverlaySettings, Func<TimeSpan> Elapsed) : base(OverlaySettings)\n        {\n            _elapsed = Elapsed;\n        }\n\n        protected override string GetText() => _elapsed().ToString();\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/ImageOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    public abstract class ImageOverlay : IOverlay\n    {\n        readonly bool _disposeImages;\n\n        protected ImageOverlay(bool DisposeImages)\n        {\n            _disposeImages = DisposeImages;\n        }\n\n        public abstract void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null);\n\n        protected void Draw(IEditableFrame Editor, IBitmapImage Image, PointF Position, SizeF? Size, int Opacity)\n        {\n            if (Image == null)\n                return;\n\n            var targetSize = Size ?? new Size(Image.Width, Image.Height);\n\n            try\n            {\n                //var point = GetPosition(new Size((int)Editor.Width, (int)Editor.Height), targetSize);\n                var destRect = new RectangleF(Position, targetSize);\n\n                Editor.DrawImage(Image, destRect, Opacity);\n            }\n            catch { }\n            finally\n            {\n                if (_disposeImages)\n                    Image.Dispose();\n            }\n        }\n\n        public virtual void Dispose() { }\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/MousePointerOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    public class MousePointerOverlay : IOverlay\n    {\n        readonly MouseOverlaySettings _settings;\n        \n        public MousePointerOverlay(MouseOverlaySettings Settings)\n        {\n            _settings = Settings;\n        }\n        \n        /// <summary>\n        /// Draws overlay.\n        /// </summary>\n        public void Draw(IEditableFrame Editor, Func<Point, Point> Transform = null)\n        {\n            if (!_settings.Display)\n                return;\n\n            var clickRadius = _settings.Radius;\n\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            var curPos = platformServices.CursorPosition;\n\n            if (Transform != null)\n                curPos = Transform(curPos);\n\n            var d = clickRadius * 2;\n\n            var x = curPos.X - clickRadius;\n            var y = curPos.Y - clickRadius;\n\n            Editor.FillEllipse(_settings.Color, new RectangleF(x, y, d, d));\n\n            var border = _settings.BorderThickness;\n\n            if (border > 0)\n            {\n                x -= border / 2;\n                y -= border / 2;\n                d += border;\n\n                Editor.DrawEllipse(_settings.BorderColor, border, new RectangleF(x, y, d, d));\n            }\n        }\n\n        public void Dispose() { }\n    }\n}\n"
  },
  {
    "path": "src/Screna/Overlays/Settings/CensorOverlaySettings.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class CensorOverlaySettings : PositionedOverlaySettings\n    {\n        public bool Display\n        {\n            get => Get(false);\n            set => Set(value);\n        }\n\n        public int Width\n        {\n            get => Get(420);\n            set => Set(value);\n        }\n\n        public int Height\n        {\n            get => Get(360);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/Settings/CustomImageOverlaySettings.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class CustomImageOverlaySettings : ImageOverlaySettings\n    {\n        public string Source\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n\n        public bool Display\n        {\n            get => Get(true);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/Settings/CustomOverlaySettings.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class CustomOverlaySettings : TextOverlaySettings\n    {\n        public string Text\n        {\n            get => Get(\"\");\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/Settings/ImageOverlaySettings.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class ImageOverlaySettings : PositionedOverlaySettings\n    {\n        public int Opacity\n        {\n            get => Get(100);\n            set => Set(value);\n        }\n\n        public bool Resize\n        {\n            get => Get<bool>();\n            set => Set(value);\n        }\n\n        public int ResizeWidth\n        {\n            get => Get(320);\n            set => Set(value);\n        }\n\n        public int ResizeHeight\n        {\n            get => Get(240);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/Overlays/TextOverlay.cs",
    "content": "﻿using System;\nusing System.Drawing;\n\nnamespace Captura.Video\n{\n    public abstract class TextOverlay : IOverlay\n    {\n        readonly TextOverlaySettings _overlaySettings;\n\n        protected TextOverlay(TextOverlaySettings OverlaySettings)\n        {\n            _overlaySettings = OverlaySettings;\n        }\n\n        public virtual void Dispose() { }\n\n        static float GetLeft(TextOverlaySettings OverlaySettings, float FullWidth, float TextWidth)\n        {\n            var x = OverlaySettings.X;\n\n            switch (OverlaySettings.HorizontalAlignment)\n            {\n                case Alignment.Start:\n                    return x;\n\n                case Alignment.End:\n                    return FullWidth - x - TextWidth - 2 * OverlaySettings.HorizontalPadding;\n\n                case Alignment.Center:\n                    return FullWidth / 2 + x - TextWidth / 2 - OverlaySettings.HorizontalPadding;\n\n                default:\n                    return 0;\n            }\n        }\n\n        static float GetTop(TextOverlaySettings OverlaySettings, float FullHeight, float TextHeight)\n        {\n            var y = OverlaySettings.Y;\n\n            switch (OverlaySettings.VerticalAlignment)\n            {\n                case Alignment.Start:\n                    return y;\n\n                case Alignment.End:\n                    return FullHeight - y - TextHeight - 2 * OverlaySettings.VerticalPadding;\n\n                case Alignment.Center:\n                    return FullHeight / 2 + y - TextHeight / 2 - OverlaySettings.VerticalPadding;\n\n                default:\n                    return 0;\n            }\n        }\n\n        protected abstract string GetText();\n        \n        public virtual void Draw(IEditableFrame Editor, Func<Point, Point> PointTransform = null)\n        {\n            if (!_overlaySettings.Display)\n                return;\n\n            var text = GetText();\n\n            if (string.IsNullOrWhiteSpace(text))\n                return;\n\n            var font = Editor.GetFont(_overlaySettings.FontFamily, _overlaySettings.FontSize);\n\n            var size = Editor.MeasureString(text, font);\n\n            int paddingX = _overlaySettings.HorizontalPadding, paddingY = _overlaySettings.VerticalPadding;\n\n            var rect = new RectangleF(GetLeft(_overlaySettings, Editor.Width, size.Width),\n                GetTop(_overlaySettings, Editor.Height, size.Height),\n                size.Width + 2 * paddingX,\n                size.Height + 2 * paddingY);\n\n            Editor.FillRectangle(_overlaySettings.BackgroundColor,\n                rect,\n                _overlaySettings.CornerRadius);\n\n            Editor.DrawString(text,\n                font,\n                _overlaySettings.FontColor,\n                new RectangleF(rect.Left + paddingX, rect.Top + paddingY, size.Width, size.Height));\n\n            var border = _overlaySettings.BorderThickness;\n\n            if (border > 0)\n            {\n                rect = new RectangleF(rect.Left - border / 2f, rect.Top - border / 2f, rect.Width + border, rect.Height + border);\n\n                Editor.DrawRectangle(_overlaySettings.BorderColor, border,\n                    rect,\n                    _overlaySettings.CornerRadius);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/Recorder.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Captura.Audio;\nusing Captura.Models;\n\n// ReSharper disable MethodSupportsCancellation\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Default implementation of <see cref=\"IRecorder\"/> interface.\n    /// Can output to <see cref=\"IVideoFileWriter\"/> or <see cref=\"IAudioFileWriter\"/>.\n    /// </summary>\n    public class Recorder : IRecorder\n    {\n        #region Fields\n        IAudioProvider _audioProvider;\n        IVideoFileWriter _videoWriter;\n        IImageProvider _imageProvider;\n\n        readonly int _frameRate;\n\n        readonly Stopwatch _sw;\n\n        readonly ManualResetEvent _continueCapturing;\n        readonly CancellationTokenSource _cancellationTokenSource;\n        readonly CancellationToken _cancellationToken;\n\n        readonly Task _recordTask;\n\n        readonly object _syncLock = new object();\n\n        Task<bool> _frameWriteTask;\n        Task _audioWriteTask;\n        int _frameCount;\n        long _audioBytesWritten;\n        readonly int _audioBytesPerFrame, _audioChunkBytes;\n        const int AudioChunkLengthMs = 200;\n        byte[] _audioBuffer, _silenceBuffer;\n\n        readonly IFpsManager _fpsManager;\n        #endregion\n\n        /// <summary>\n        /// Creates a new instance of <see cref=\"IRecorder\"/> writing to <see cref=\"IVideoFileWriter\"/>.\n        /// </summary>\n        /// <param name=\"VideoWriter\">The <see cref=\"IVideoFileWriter\"/> to write to.</param>\n        /// <param name=\"ImageProvider\">The image source.</param>\n        /// <param name=\"FrameRate\">Video Frame Rate.</param>\n        /// <param name=\"AudioProvider\">The audio source. null = no audio.</param>\n        public Recorder(IVideoFileWriter VideoWriter, IImageProvider ImageProvider, int FrameRate,\n            IAudioProvider AudioProvider = null,\n            IFpsManager FpsManager = null)\n        {\n            _videoWriter = VideoWriter ?? throw new ArgumentNullException(nameof(VideoWriter));\n            _imageProvider = ImageProvider ?? throw new ArgumentNullException(nameof(ImageProvider));\n            _audioProvider = AudioProvider;\n            _fpsManager = FpsManager;\n\n            _cancellationTokenSource = new CancellationTokenSource();\n            _cancellationToken = _cancellationTokenSource.Token;\n\n            if (FrameRate <= 0)\n                throw new ArgumentException(\"Frame Rate must be possitive\", nameof(FrameRate));\n\n            _frameRate = FrameRate;\n\n            _continueCapturing = new ManualResetEvent(false);\n\n            if (VideoWriter.SupportsAudio && AudioProvider != null)\n            {\n                var wf = AudioProvider.WaveFormat;\n\n                _audioBytesPerFrame = (int) ((1.0 / FrameRate)\n                                             * wf.SampleRate\n                                             * wf.Channels\n                                             * (wf.BitsPerSample / 8.0));\n\n                _audioChunkBytes = (int) (_audioBytesPerFrame * (FrameRate * AudioChunkLengthMs / 1000.0));\n            }\n            else _audioProvider = null;\n\n            _sw = new Stopwatch();\n\n            _recordTask = Task.Factory.StartNew(async () => await DoRecord(), TaskCreationOptions.LongRunning);\n        }\n\n        async Task DoRecord()\n        {\n            try\n            {\n                var frameInterval = TimeSpan.FromSeconds(1.0 / _frameRate);\n                _frameCount = 0;\n\n                // Returns false when stopped\n\n                while (_continueCapturing.WaitOne() && !_cancellationToken.IsCancellationRequested)\n                {\n                    var timestamp = _sw.Elapsed;\n\n                    if (_frameWriteTask != null)\n                    {\n                        // If false, stop recording\n                        if (!await _frameWriteTask)\n                            return;\n\n                        if (!WriteDuplicateFrame())\n                            return;\n                    }\n\n                    if (_audioWriteTask != null)\n                    {\n                        await _audioWriteTask;\n                    }\n\n                    _frameWriteTask = Task.Run(() => FrameWriter(timestamp));\n\n                    var timeTillNextFrame = timestamp + frameInterval - _sw.Elapsed;\n\n                    if (timeTillNextFrame > TimeSpan.Zero)\n                        Thread.Sleep(timeTillNextFrame);\n                }\n            }\n            catch (Exception e)\n            {\n                lock (_syncLock)\n                {\n                    if (!_disposed)\n                    {\n                        ErrorOccurred?.Invoke(e);\n\n                        Dispose(false);\n                    }\n                }\n            }\n        }\n\n        bool FrameWriter(TimeSpan Timestamp)\n        {\n            var editableFrame = _imageProvider.Capture();\n\n            var frame = editableFrame.GenerateFrame(Timestamp);\n\n            var success = AddFrame(frame);\n\n            if (!success)\n            {\n                return false;\n            }\n\n            _fpsManager?.OnFrame();\n\n            try\n            {\n                _audioWriteTask = Task.Run(WriteAudio);\n\n                return true;\n            }\n            catch (InvalidOperationException)\n            {\n                return false;\n            }\n        }\n\n        bool WriteDuplicateFrame()\n        {\n            var requiredFrames = _sw.Elapsed.TotalSeconds * _frameRate;\n            var diff = requiredFrames - _frameCount;\n\n            // Write atmost 1 duplicate frame\n            if (diff >= 1)\n            {\n                if (!AddFrame(RepeatFrame.Instance))\n                    return false;\n            }\n\n            return true;\n        }\n\n        bool AddFrame(IBitmapFrame Frame)\n        {\n            try\n            {\n                _videoWriter.WriteFrame(Frame);\n\n                ++_frameCount;\n\n                return true;\n            }\n            catch (InvalidOperationException)\n            {\n                return false;\n            }\n        }\n\n        void WriteAudio()\n        {\n            if (_audioProvider == null)\n            {\n                return;\n            }\n\n            // These values need to be long otherwise can get out of range in a few hours\n            var shouldHaveWritten = (_frameCount - 1L) * _audioBytesPerFrame;\n\n            // Already written more than enough, skip for now\n            if (_audioBytesWritten >= shouldHaveWritten)\n            {\n                return;\n            }\n\n            var toWrite = (int)(shouldHaveWritten - _audioBytesWritten);\n\n            // Only write if data to write is more than chunk size.\n            // This gives enough time for the audio provider to buffer data from the source.\n            if (toWrite < _audioChunkBytes)\n            {\n                return;\n            }\n\n            // Reallocate buffer as needed\n            if (_audioBuffer == null || _audioBuffer.Length < toWrite)\n            {\n                _audioBuffer = new byte[toWrite];\n            }\n\n            var read = _audioProvider.Read(_audioBuffer, 0, toWrite);\n\n            // Nothing read\n            if (read == 0)\n            {\n                return;\n            }\n\n            _videoWriter.WriteAudio(_audioBuffer, 0, read);\n            _audioBytesWritten += read;\n\n            // Fill with silence to maintain synchronization\n            var silenceToWrite = toWrite - read;\n\n            // Write silence only when more than a threshold\n            // Threshold should ideally be a bit greater than chunk size\n            if (silenceToWrite <= _audioChunkBytes * 1.5)\n            {\n                return;\n            }\n            \n            // Reallocate silence buffer: An array of zeros.\n            if (_silenceBuffer == null || _silenceBuffer.Length < silenceToWrite)\n            {\n                _silenceBuffer = new byte[silenceToWrite];\n            }\n\n            _videoWriter.WriteAudio(_silenceBuffer, 0, silenceToWrite);\n            _audioBytesWritten += silenceToWrite;\n        }\n\n        #region Dispose\n        async void Dispose(bool TerminateRecord)\n        {\n            if (_disposed)\n                return;\n\n            _disposed = true;\n\n            _cancellationTokenSource.Cancel();\n\n            // Resume record loop if paused so it can exit\n            _continueCapturing.Set();\n\n            // Ensure all threads exit before disposing resources.\n            if (TerminateRecord)\n                _recordTask.Wait();\n\n            try\n            {\n                if (_frameWriteTask != null)\n                    await _frameWriteTask;\n            }\n            catch { }\n\n            try\n            {\n                if (_audioWriteTask != null)\n                    await _audioWriteTask;\n            }\n            catch { }\n\n            if (_audioProvider != null)\n            {\n                _audioProvider.Stop();\n                _audioProvider.Dispose();\n                _audioProvider = null;\n            }\n\n            _imageProvider?.Dispose();\n            _imageProvider = null;\n\n            _videoWriter.Dispose();\n            _videoWriter = null;\n\n            _audioBuffer = _silenceBuffer = null;\n\n            _continueCapturing.Dispose();\n        }\n\n        /// <summary>\n        /// Frees all resources used by this instance.\n        /// </summary>\n        public void Dispose()\n        {\n            lock (_syncLock)\n            {\n                Dispose(true);\n            }\n        }\n\n        bool _disposed;\n\n        /// <summary>\n        /// Fired when an error occurs\n        /// </summary>\n        public event Action<Exception> ErrorOccurred;\n\n        void ThrowIfDisposed()\n        {\n            lock (_syncLock)\n            {\n                if (_disposed)\n                    throw new ObjectDisposedException(\"this\");\n            }\n        }\n        #endregion\n\n        /// <summary>\n        /// Start Recording.\n        /// </summary>\n        public void Start()\n        {\n            ThrowIfDisposed();\n\n            _sw?.Start();\n\n            _audioProvider?.Start();\n            \n            _continueCapturing?.Set();\n        }\n\n        /// <summary>\n        /// Stop Recording.\n        /// </summary>\n        public void Stop()\n        {\n            ThrowIfDisposed();\n\n            _continueCapturing?.Reset();\n            _audioProvider?.Stop();\n\n            _sw?.Stop();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Screna/RegionItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class RegionItem : NotifyPropertyChanged, IVideoItem\n    {\n        readonly IRegionProvider _selector;\n        readonly IPlatformServices _platformServices;\n\n        public RegionItem(IRegionProvider RegionSelector, IPlatformServices PlatformServices)\n        {\n            _selector = RegionSelector;\n            _platformServices = PlatformServices;\n        }\n\n        public IImageProvider GetImageProvider(bool IncludeCursor)\n        {\n            return _platformServices.GetRegionProvider(_selector.SelectedRegion,\n                IncludeCursor,\n                () => _selector.SelectedRegion.Location);\n        }\n\n        string _name;\n\n        public string Name\n        {\n            get => _name;\n            set => Set(ref _name, value);\n        }\n\n        public override string ToString() => Name;\n    }\n}\n"
  },
  {
    "path": "src/Screna/ScreenShot.cs",
    "content": "﻿using System.Drawing;\n\nnamespace Captura.Video\n{\n    /// <summary>\n    /// Contains methods for taking ScreenShots\n    /// </summary>\n    public static class ScreenShot\n    {\n        /// <summary>\n        /// Captures the entire Desktop.\n        /// </summary>\n        /// <param name=\"IncludeCursor\">Whether to include the Mouse Cursor.</param>\n        /// <returns>The Captured Image.</returns>\n        public static IBitmapImage Capture(bool IncludeCursor = false)\n        {\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            return Capture(platformServices.DesktopRectangle, IncludeCursor);\n        }\n\n        /// <summary>\n        /// Capture transparent Screenshot of a Window.\n        /// </summary>\n        /// <param name=\"Window\">The <see cref=\"IWindow\"/> to Capture.</param>\n        /// <param name=\"IncludeCursor\">Whether to include Mouse Cursor.</param>\n        public static IBitmapImage CaptureTransparent(IWindow Window, bool IncludeCursor = false)\n        {\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            return platformServices.CaptureTransparent(Window, IncludeCursor);\n        }\n        \n        /// <summary>\n        /// Captures a Specific Region.\n        /// </summary>\n        /// <param name=\"Region\">A <see cref=\"Rectangle\"/> specifying the Region to Capture.</param>\n        /// <param name=\"IncludeCursor\">Whether to include the Mouse Cursor.</param>\n        /// <returns>The Captured Image.</returns>\n        public static IBitmapImage Capture(Rectangle Region, bool IncludeCursor = false)\n        {\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            return platformServices.Capture(Region, IncludeCursor);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Screna/Screna.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Loc\\Captura.Loc.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Screna/Timing.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace Captura.Models\n{\n    public class Timing\n    {\n        TimeSpan _addend;\n        readonly Stopwatch _stopwatch = new Stopwatch();\n\n        public TimeSpan Elapsed => _stopwatch.Elapsed + _addend;\n\n        public void Start()\n        {\n            _stopwatch.Start();\n        }\n\n        public void Pause()\n        {\n            _addend += _stopwatch.Elapsed;\n\n            _stopwatch.Reset();\n        }\n\n        public void Stop()\n        {\n            _addend = TimeSpan.Zero;\n\n            _stopwatch.Reset();\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/VideoItems/FullScreenItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    class FullScreenItem : NotifyPropertyChanged, IVideoItem\n    {\n        readonly IPlatformServices _platformServices;\n        readonly VideoSettings _videoSettings;\n\n        public FullScreenItem(IPlatformServices PlatformServices, VideoSettings VideoSettings)\n        {\n            _platformServices = PlatformServices;\n            _videoSettings = VideoSettings;\n        }\n\n        public override string ToString() => Name;\n\n        public string Name => null;\n\n        public IImageProvider GetImageProvider(bool IncludeCursor)\n        {\n            return _platformServices.GetAllScreensProvider(IncludeCursor,\n                _videoSettings.RecorderMode == RecorderMode.Steps);\n\t\t}\n    }\n}"
  },
  {
    "path": "src/Screna/VideoItems/ScreenItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class ScreenItem : NotifyPropertyChanged, IVideoItem\n    {\n        readonly IPlatformServices _platformServices;\n        readonly VideoSettings _videoSettings;\n\n        public IScreen Screen { get; }\n\n        public ScreenItem(IScreen Screen,\n            IPlatformServices PlatformServices,\n            VideoSettings VideoSettings)\n        {\n            this.Screen = Screen;\n            _platformServices = PlatformServices;\n            _videoSettings = VideoSettings;\n        }\n\n        public string Name => Screen.DeviceName;\n\n        public override string ToString() => Name;\n\n        public IImageProvider GetImageProvider(bool IncludeCursor)\n        {\n            return _platformServices.GetScreenProvider(Screen, IncludeCursor, _videoSettings.RecorderMode == RecorderMode.Steps);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/VideoItems/WaveItem.cs",
    "content": "﻿namespace Captura.Audio\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class WaveItem : IAudioWriterItem\n    {\n        public string Name { get; } = \"Wave\";\n        public string Extension { get; } = \".wav\";\n\n        public IAudioFileWriter GetAudioFileWriter(string FileName, WaveFormat Wf, int AudioQuality)\n        {\n            return new AudioFileWriter(FileName, Wf);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Screna/VideoItems/WindowItem.cs",
    "content": "﻿namespace Captura.Video\n{\n    public class WindowItem : NotifyPropertyChanged, IVideoItem\n    {\n        readonly IPlatformServices _platformServices;\n\n        public IWindow Window { get; }\n\n        public WindowItem(IWindow Window, IPlatformServices PlatformServices)\n        {\n            this.Window = Window;\n            _platformServices = PlatformServices;\n            Name = Window.Title;\n        }\n\n        public override string ToString() => Name;\n\n        public string Name { get; }\n\n        public IImageProvider GetImageProvider(bool IncludeCursor)\n        {\n            if (!Window.IsAlive)\n            {\n                throw new WindowClosedException();\n            }\n\n            return _platformServices.GetWindowProvider(Window, IncludeCursor);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/VideoSourceProviders/FullScreenSourceProvider.cs",
    "content": "using Captura.Loc;\n\nnamespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class FullScreenSourceProvider : VideoSourceProviderBase\n    {\n        public FullScreenSourceProvider(ILocalizationProvider Loc,\n            IIconSet Icons,\n            IPlatformServices PlatformServices,\n            VideoSettings VideoSettings) : base(Loc)\n        {\n            Source = new FullScreenItem(PlatformServices, VideoSettings);\n            Icon = Icons.MultipleMonitor;\n        }\n\n        public override IVideoItem Source { get; }\n\n        public override string Name => Loc.FullScreen;\n\n        public override string Description { get; } = \"Record Fullscreen.\";\n\n        public override string Icon { get; }\n\n        public override string Serialize() => \"\";\n\n        public override bool Deserialize(string Serialized) => true;\n\n        public override bool ParseCli(string Arg)\n        {\n            return string.IsNullOrWhiteSpace(Arg) || Arg == \"desktop\";\n        }\n\n        public override IBitmapImage Capture(bool IncludeCursor)\n        {\n            return ScreenShot.Capture(IncludeCursor);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/VideoSourceProviders/RegionSourceProvider.cs",
    "content": "using System.Drawing;\nusing Captura.Loc;\n\nnamespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class RegionSourceProvider : VideoSourceProviderBase\n    {\n        readonly IRegionProvider _regionProvider;\n        readonly IVideoSourcePicker _videoSourcePicker;\n\n        public RegionSourceProvider(ILocalizationProvider Loc,\n            IRegionProvider RegionProvider,\n            IVideoSourcePicker VideoSourcePicker,\n            IIconSet Icons) : base(Loc)\n        {\n            _videoSourcePicker = VideoSourcePicker;\n            _regionProvider = RegionProvider;\n\n            Source = RegionProvider.VideoSource;\n            Icon = Icons.Region;\n        }\n\n        public override IVideoItem Source { get; }\n\n        public override string Name => Loc.Region;\n\n        public override string Description { get; } = \"Record region selected using Region Selector.\";\n\n        public override string Icon { get; }\n\n        // Prevents opening multiple region pickers at the same time\n        bool _picking;\n\n        public override bool OnSelect()\n        {\n            if (_picking)\n                return false;\n\n            _picking = true;\n\n            try\n            {\n                var wasVisible = _regionProvider.SelectorVisible;\n\n                _regionProvider.SelectorVisible = false;\n\n                var region = _videoSourcePicker.PickRegion();\n\n                if (region == null)\n                {\n                    // Show again if was already visible\n                    _regionProvider.SelectorVisible = wasVisible;\n\n                    return false;\n                }\n\n                _regionProvider.SelectedRegion = region.Value;\n\n                _regionProvider.SelectorVisible = true;\n            }\n            finally\n            {\n                _picking = false;\n            }\n\n            return true;\n        }\n\n        public override void OnUnselect()\n        {\n            _regionProvider.SelectorVisible = false;\n        }\n\n        public override string Serialize()\n        {\n            var rect = _regionProvider.SelectedRegion;\n            return rect.ConvertToString();\n        }\n\n        public override bool Deserialize(string Serialized)\n        {\n            if (!(Serialized.ConvertToRectangle() is Rectangle rect))\n                return false;\n\n            _regionProvider.SelectedRegion = rect;\n\n            _regionProvider.SelectorVisible = true;\n\n            return true;\n        }\n\n        public override bool ParseCli(string Arg)\n        {\n            if (!(Arg.ConvertToRectangle() is Rectangle rect))\n                return false;\n\n            _regionProvider.SelectedRegion = rect.Even();\n\n            return true;\n        }\n\n        public override IBitmapImage Capture(bool IncludeCursor)\n        {\n            return ScreenShot.Capture(_regionProvider.SelectedRegion, IncludeCursor);\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/VideoSourceProviders/ScreenSourceProvider.cs",
    "content": "using System.Linq;\nusing System.Text.RegularExpressions;\nusing Captura.Loc;\n\nnamespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class ScreenSourceProvider : VideoSourceProviderBase\n    {\n        readonly IVideoSourcePicker _videoSourcePicker;\n        readonly IPlatformServices _platformServices;\n        readonly VideoSettings _videoSettings;\n\n        public ScreenSourceProvider(ILocalizationProvider Loc,\n            IVideoSourcePicker VideoSourcePicker,\n            IIconSet Icons,\n            IPlatformServices PlatformServices,\n            VideoSettings VideoSettings) : base(Loc)\n        {\n            _videoSourcePicker = VideoSourcePicker;\n            _platformServices = PlatformServices;\n            _videoSettings = VideoSettings;\n\n            Icon = Icons.Screen;\n        }\n\n        bool PickScreen()\n        {\n            var screen = _videoSourcePicker.PickScreen();\n\n            if (screen == null)\n                return false;\n\n            _source = new ScreenItem(screen, _platformServices, _videoSettings);\n            RaisePropertyChanged(nameof(Source));\n            return true;\n        }\n\n        void Set(IScreen Screen)\n        {\n            _source = new ScreenItem(Screen, _platformServices, _videoSettings);\n            RaisePropertyChanged(nameof(Source));\n        }\n\n        IVideoItem _source;\n\n        public override IVideoItem Source => _source;\n\n        public override string Name => Loc.Screen;\n\n        public override string Description { get; } = \"Record a specific screen.\";\n\n        public override string Icon { get; }\n\n        public override bool OnSelect()\n        {\n            var screens = _platformServices.EnumerateScreens().ToArray();\n\n            // Select first screen if there is only one\n            if (screens.Length == 1)\n            {\n                Set(screens[0]);\n                return true;\n            }\n\n            return PickScreen();\n        }\n\n        public override bool Deserialize(string Serialized)\n        {\n            var screen = _platformServices.EnumerateScreens()\n                .FirstOrDefault(M => M.DeviceName == Serialized);\n\n            if (screen == null)\n                return false;\n\n            Set(screen);\n\n            return true;\n        }\n\n        public override bool ParseCli(string Arg)\n        {\n            if (!Regex.IsMatch(Arg, @\"^screen:\\d+$\"))\n                return false;\n\n            var index = int.Parse(Arg.Substring(7));\n\n            var screens = _platformServices.EnumerateScreens().ToArray();\n\n            if (index >= screens.Length)\n                return false;\n\n            Set(screens[index]);\n\n            return true;\n        }\n\n        public override IBitmapImage Capture(bool IncludeCursor)\n        {\n            if (Source is ScreenItem screenItem)\n            {\n                return ScreenShot.Capture(screenItem.Screen.Rectangle, IncludeCursor);\n            }\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "src/Screna/VideoSourceProviders/VideoSourceProviderBase.cs",
    "content": "using Captura.Loc;\n\nnamespace Captura.Video\n{\n    public abstract class VideoSourceProviderBase : NotifyPropertyChanged, IVideoSourceProvider\n    {\n        protected readonly ILocalizationProvider Loc;\n\n        protected VideoSourceProviderBase(ILocalizationProvider Loc)\n        {\n            this.Loc = Loc;\n\n            Loc.LanguageChanged += L => RaisePropertyChanged(nameof(Name));\n        }\n\n        public virtual bool SupportsStepsMode => true;\n\n        public abstract IVideoItem Source { get; }\n\n        public abstract string Name { get; }\n\n        public abstract string Description { get; }\n\n        public abstract string Icon { get; }\n\n        public abstract IBitmapImage Capture(bool IncludeCursor);\n\n        public virtual bool OnSelect() => true;\n\n        public virtual void OnUnselect() { }\n\n        public virtual string Serialize()\n        {\n            return Source.ToString();\n        }\n\n        public abstract bool Deserialize(string Serialized);\n\n        public abstract bool ParseCli(string Arg);\n    }\n}"
  },
  {
    "path": "src/Screna/VideoSourceProviders/WindowSourceProvider.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing Captura.Loc;\n\nnamespace Captura.Video\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class WindowSourceProvider : VideoSourceProviderBase\n    {\n        readonly IVideoSourcePicker _videoSourcePicker;\n        readonly IRegionProvider _regionProvider;\n        readonly IPlatformServices _platformServices;\n\n        public WindowSourceProvider(ILocalizationProvider Loc,\n            IVideoSourcePicker VideoSourcePicker,\n            IRegionProvider RegionProvider,\n            IIconSet Icons,\n            IPlatformServices PlatformServices) : base(Loc)\n        {\n            _videoSourcePicker = VideoSourcePicker;\n            _regionProvider = RegionProvider;\n            _platformServices = PlatformServices;\n\n            Icon = Icons.Window;\n        }\n\n        bool PickWindow()\n        {\n            var window = _videoSourcePicker.PickWindow(M => M.Handle != _regionProvider.Handle);\n\n            if (window == null)\n                return false;\n\n            _source = new WindowItem(window, _platformServices);\n\n            RaisePropertyChanged(nameof(Source));\n            return true;\n        }\n\n        void Set(IWindow Window)\n        {\n            _source = new WindowItem(Window, _platformServices);\n            RaisePropertyChanged(nameof(Source));\n        }\n\n        IVideoItem _source;\n\n        public override IVideoItem Source => _source;\n\n        public override string Name => Loc.Window;\n\n        public override string Description { get; } = @\"Record a specific window.\nThe video is of the initial size of the window.\";\n\n        public override string Icon { get; }\n\n        public override bool OnSelect()\n        {\n            return PickWindow();\n        }\n\n        public override bool Deserialize(string Serialized)\n        {\n            var window = _platformServices.EnumerateWindows()\n                .FirstOrDefault(M => M.Title == Serialized);\n\n            if (window == null)\n                return false;\n\n            Set(window);\n\n            return true;\n        }\n\n        public override bool ParseCli(string Arg)\n        {\n            if (!Regex.IsMatch(Arg, @\"^win:-?\\d+$\"))\n                return false;\n\n            var handle = new IntPtr(int.Parse(Arg.Substring(4)));\n\n            Set(_platformServices.GetWindow(handle));\n\n            return true;\n        }\n\n        public override IBitmapImage Capture(bool IncludeCursor)\n        {\n            if (Source is WindowItem windowItem)\n            {\n                return ScreenShot.Capture(windowItem.Window.Rectangle, IncludeCursor);\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Tests/AudioFileWriterTests.cs",
    "content": "﻿using System;\nusing System.IO;\nusing Captura.Audio;\nusing Xunit;\n\nnamespace Captura.Tests\n{\n    [Collection(nameof(Tests))]\n    public class AudioFileWriterTests\n    {\n        [Fact]\n        public void NullAudioOutputStream()\n        {\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                using (new AudioFileWriter(OutStream: null, Format: new WaveFormat())) { }\n            });\n        }\n\n        [Fact]\n        public void NullWaveFormat()\n        {\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                using (new AudioFileWriter(Stream.Null, null)) { }\n            });\n        }\n\n        [Fact]\n        public void NullFileName()\n        {\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                using (new AudioFileWriter(FileName: null, Format: new WaveFormat())) { }\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/ConsoleStartTests.cs",
    "content": "﻿using System.Diagnostics;\nusing System.Threading;\nusing Xunit;\n\nnamespace Captura.Tests.Console\n{\n    [Collection(nameof(Tests))]\n    public class ConsoleStartTests\n    {\n        static Process Start(string Arguments)\n        {\n            var path = TestManagerFixture.GetCliPath();\n\n            var process = new Process\n            {\n                StartInfo =\n                {\n                    FileName = path,\n                    Arguments = Arguments,\n                    UseShellExecute = false,\n                    CreateNoWindow = true,\n                    RedirectStandardInput = true,\n                    RedirectStandardOutput = true,\n                    RedirectStandardError = true\n                },\n                EnableRaisingEvents = true\n            };\n\n            process.Start();\n\n            process.BeginErrorReadLine();\n            process.BeginOutputReadLine();\n\n            void Write(string Data, string Prefix)\n            {\n                if (string.IsNullOrWhiteSpace(Data))\n                    return;\n\n                Trace.WriteLine($\"{Prefix}: {Data}\");\n            }\n\n            process.ErrorDataReceived += (S, E) => Write(E.Data, \"Err\");\n            process.OutputDataReceived += (S, E) => Write(E.Data, \"Out\");\n\n            return process;\n        }\n        \n        [Fact]\n        public void StartSharpAvi()\n        {\n            var process = Start(\"start --encoder sharpavi:0\");\n\n            Thread.Sleep(1000);\n\n            process.StandardInput.WriteLine('q');\n\n            process.WaitForExit();\n\n            Assert.Equal(0, process.ExitCode);\n        }\n\n        // TODO: Don't skip this test\n        [Fact(Skip = \"This is failing on AppVeyor\")]\n        public void StartSharpAviFixedDuration()\n        {\n            var process = Start(\"start --encoder sharpavi:0 --length 1\");\n\n            process.WaitForExit();\n\n            Assert.Equal(0, process.ExitCode);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Tests/Fixtures/AppRunnerFixture.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing TestStack.White;\nusing TestStack.White.UIItems.WindowItems;\n\nnamespace Captura.Tests.Views\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class AppRunnerFixture : IDisposable\n    {\n        public Application App { get; }\n        public Window MainWindow { get; }\n\n        public AppRunnerFixture()\n        {\n            App = Application.Launch(new ProcessStartInfo(TestManagerFixture.GetUiPath(), \"--no-persist\"));\n\n            MainWindow = App.GetWindow(nameof(Captura));\n        }\n\n        public void Dispose()\n        {\n            MainWindow.Close();\n\n            App.Close();\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/Fixtures/MoqFixture.cs",
    "content": "﻿using System;\nusing Captura.Audio;\nusing Captura.Video;\nusing Moq;\n\nnamespace Captura.Tests\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class MoqFixture : IDisposable\n    {\n        public void Dispose() { }\n\n        public Mock<IImageProvider> GetImageProviderMock(int Width = 100, int Height = 50)\n        {\n            var mock = new Mock<IImageProvider>();\n\n            mock.Setup(M => M.Width).Returns(Width);\n\n            mock.Setup(M => M.Height).Returns(Height);\n\n            var editorMock = new Mock<IEditableFrame>();\n            editorMock.Setup(M => M.Width).Returns(Width);\n            editorMock.Setup(M => M.Height).Returns(Height);\n\n            mock.Setup(M => M.Capture()).Returns(editorMock.Object);\n\n            return mock;\n        }\n\n        public Mock<IAudioProvider> GetAudioProviderMock()\n        {\n            var mock = new Mock<IAudioProvider>();\n\n            mock.Setup(M => M.WaveFormat).Returns(new WaveFormat());\n\n            return mock;\n        }\n\n        public Mock<IAudioFileWriter> GetAudioFileWriterMock()\n        {\n            return new Mock<IAudioFileWriter>();\n        }\n\n        public Mock<IVideoFileWriter> GetVideoFileWriterMock()\n        {\n            var mock = new Mock<IVideoFileWriter>();\n\n            mock.Setup(M => M.WriteFrame(It.IsAny<IBitmapFrame>()))\n                .Callback<IBitmapFrame>(M => M.Dispose());\n\n            mock.Setup(M => M.SupportsAudio).Returns(true);\n\n            return mock;\n        }\n\n        public Mock<IOverlay> GetOverlayMock()\n        {\n            return new Mock<IOverlay>();\n        }\n\n        public T GetService<T>() => ServiceProvider.Get<T>();\n    }\n}"
  },
  {
    "path": "src/Tests/Fixtures/TestCollection.cs",
    "content": "﻿using Xunit;\n\nnamespace Captura.Tests.Fixtures\n{\n    [CollectionDefinition(nameof(Tests))]\n    public class TestCollection : ICollectionFixture<TestManagerFixture>, ICollectionFixture<MoqFixture> { }\n}"
  },
  {
    "path": "src/Tests/Fixtures/TestManagerFixture.cs",
    "content": "﻿using System;\nusing System.IO;\nusing Captura.Fakes;\nusing Captura.Video;\n\nnamespace Captura.Tests\n{\n    // ReSharper disable once ClassNeverInstantiated.Global\n    public class TestManagerFixture : IDisposable\n    {\n        public TestManagerFixture()\n        {\n            ServiceProvider.LoadModule(new CoreModule());\n\n            ServiceProvider.LoadModule(new FakesModule());\n        }\n\n        public void Dispose() { }\n\n        static string GetPath(string FolderName, string FileName)\n        {\n            var path = typeof(IOverlay).Assembly.CodeBase\n                .Split(new [] {\"///\"}, StringSplitOptions.None)[1];\n\n#if DEBUG\n            const string config = \"Debug\";\n#else\n            const string config = \"Release\";\n#endif\n\n            for (var i = 0; i < 5; ++i)\n                path = Path.GetDirectoryName(path);\n\n            return Path.Combine(path, $\"{FolderName}/bin/{config}/{FileName}\");\n        }\n\n        public static string GetCliPath()\n        {\n            return GetPath(\"Captura.Console\", \"captura-cli.exe\");\n        }\n\n        public static string GetUiPath()\n        {\n            return GetPath(nameof(Captura), \"captura.exe\");\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/ImageProviderTests.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing Captura.Video;\nusing Moq;\nusing Xunit;\n\nnamespace Captura.Tests\n{\n    [Collection(nameof(Tests))]\n    public class ImageProviderTests\n    {\n        readonly MoqFixture _moq;\n\n        public ImageProviderTests(MoqFixture Moq)\n        {\n            _moq = Moq;\n        }\n\n        [Fact]\n        public void OverlayImageProviderNull()\n        {\n            var overlay = _moq.GetOverlayMock().Object;\n\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                using (new OverlayedImageProvider(null, overlay)) { }\n            });\n        }\n\n        [Fact]\n        public void OverlaysNull()\n        {\n            var imageProvider = _moq.GetImageProviderMock().Object;\n\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                using (new OverlayedImageProvider(imageProvider, null)) { }\n            });\n        }\n\n        [Fact]\n        public void WindowProviderNull()\n        {\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                var platformServices = _moq.GetService<IPlatformServices>();\n\n                using (platformServices.GetWindowProvider(null, false)) { }\n            });\n        }\n\n        [Fact]\n        public void RegionImageSize()\n        {\n            var rect = new Rectangle(0, 0, 100, 100);\n\n            var platformServices = _moq.GetService<IPlatformServices>();\n\n            using var imgProvider = platformServices.GetRegionProvider(rect, false);\n            Assert.Equal(imgProvider.Width, rect.Width);\n            Assert.Equal(imgProvider.Height, rect.Height);\n\n            using var img = imgProvider.Capture();\n            Assert.Equal(img.Width, rect.Width);\n            Assert.Equal(img.Height, rect.Height);\n        }\n\n        [Fact]\n        public void RegionImageSizeOdd()\n        {\n            var rect = new Rectangle(0, 0, 101, 53);\n\n            var platformServices = _moq.GetService<IPlatformServices>();\n\n            using var imgProvider = platformServices.GetRegionProvider(rect, false);\n            Assert.True(imgProvider.Width % 2 == 0);\n            Assert.True(imgProvider.Height % 2 == 0);\n\n            using var img = imgProvider.Capture();\n            Assert.Equal(img.Width, imgProvider.Width);\n            Assert.Equal(img.Height, imgProvider.Height);\n\n            Assert.True(img.Width % 2 == 0);\n            Assert.True(img.Height % 2 == 0);\n        }\n\n        [Fact]\n        public void OverlayedSize()\n        {\n            var imgProvider = _moq.GetImageProviderMock().Object;\n            var overlay = _moq.GetOverlayMock().Object;\n\n            using var provider = new OverlayedImageProvider(imgProvider, overlay);\n            Assert.Equal(provider.Width, imgProvider.Width);\n            Assert.Equal(provider.Height, imgProvider.Height);\n\n            using var img = provider.Capture();\n            Assert.Equal(provider.Width, img.Width);\n            Assert.Equal(provider.Height, img.Height);\n        }\n\n        [Fact]\n        public void CaptureOverlayedImage()\n        {\n            var imgProviderMock = _moq.GetImageProviderMock();\n            var overlayMock = _moq.GetOverlayMock();\n\n            using (var provider = new OverlayedImageProvider(imgProviderMock.Object, overlayMock.Object))\n            {\n                using (provider.Capture())\n                {\n                    imgProviderMock.Verify(M => M.Capture(), Times.Once);\n                    overlayMock.Verify(M => M.Draw(It.IsAny<IEditableFrame>(), It.IsAny<Func<Point, Point>>()), Times.Once);\n                }\n            }\n\n            imgProviderMock.Verify(M => M.Dispose(), Times.Once);\n            overlayMock.Verify(M => M.Dispose(), Times.Once);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/Models/FakePropertyStore.cs",
    "content": "﻿namespace Captura.Tests\n{\n    public class FakePropertyStore : PropertyStore\n    {\n        public const string DefaultPropertyValue = \"Default Value\";\n        \n        public string Property\n        {\n            get => Get(DefaultPropertyValue);\n            set => Set(value);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/PropertyStoreTests.cs",
    "content": "﻿using Xunit;\n\nnamespace Captura.Tests\n{\n    [Collection(nameof(Tests))]\n    public class PropertyStoreTests\n    {\n        [Fact]\n        public void TestPropertyChanged()\n        {\n            var obj = new FakePropertyStore();\n\n            var propertyName = \"Unknown\";\n\n            obj.PropertyChanged += (S, E) => propertyName = E.PropertyName;\n\n            const string newValue = \"New Value\";\n\n            obj.Property = newValue;\n\n            Assert.Equal(obj.Property, newValue);\n            Assert.Equal(nameof(obj.Property), propertyName);\n        }\n\n        [Fact]\n        public void CheckDefaultValue()\n        {\n            var obj = new FakePropertyStore();\n            \n            Assert.Equal(obj.Property, FakePropertyStore.DefaultPropertyValue);\n        }\n    }\n}"
  },
  {
    "path": "src/Tests/RecorderTests.cs",
    "content": "﻿using System;\nusing Captura.Audio;\nusing Captura.Video;\nusing Moq;\nusing Xunit;\n\nnamespace Captura.Tests\n{\n    [Collection(nameof(Tests))]\n    public class RecorderTests\n    {\n        readonly MoqFixture _moq;\n\n        public RecorderTests(MoqFixture Moq)\n        {\n            _moq = Moq;\n        }\n\n        [Fact]\n        public void NullVideoWriter()\n        {\n            var imageProvider = _moq.GetImageProviderMock().Object;\n\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                using (new Recorder(null, imageProvider, 10)) { }\n            });\n        }\n\n        [Fact]\n        public void NullImageProvider()\n        {\n            var videoWriter = _moq.GetVideoFileWriterMock().Object;\n\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                using (new Recorder(videoWriter, null, 10)) { }\n            });\n        }\n\n        [Fact]\n        public void NullAudioWriter()\n        {\n            var audioProvider = _moq.GetAudioProviderMock().Object;\n\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                using (new AudioRecorder(null, audioProvider)) { }\n            });\n        }\n\n        [Fact]\n        public void NullAudioProvider()\n        {\n            var audioWriter = _moq.GetAudioFileWriterMock().Object;\n\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                using (new AudioRecorder(audioWriter, null)) { }\n            });\n        }\n\n        [Fact]\n        public void NegativeFrameRate()\n        {\n            var imageProvider = _moq.GetImageProviderMock().Object;\n            var videoWriter = _moq.GetVideoFileWriterMock().Object;\n\n            Assert.Throws<ArgumentException>(() =>\n            {\n                using (new Recorder(videoWriter, imageProvider, -1)) { }\n            });\n        }\n\n        [Fact]\n        public void ZeroFrameRate()\n        {\n            var imageProvider = _moq.GetImageProviderMock().Object;\n            var videoWriter = _moq.GetVideoFileWriterMock().Object;\n\n            Assert.Throws<ArgumentException>(() =>\n            {\n                using (new Recorder(videoWriter, imageProvider, 0)) { }\n            });\n        }\n\n        [Fact]\n        public void RecorderVideoDispose()\n        {\n            var imgProviderMock = _moq.GetImageProviderMock();\n            var videoWriterMock = _moq.GetVideoFileWriterMock();\n            var audioProviderMock = _moq.GetAudioProviderMock();\n\n            using (new Recorder(videoWriterMock.Object, imgProviderMock.Object, 10, audioProviderMock.Object)) \n            {\n            }\n\n            imgProviderMock.Verify(M => M.Dispose(), Times.Once);\n            videoWriterMock.Verify(M => M.Dispose(), Times.Once);\n            audioProviderMock.Verify(M => M.Dispose(), Times.Once);\n        }\n\n        [Fact]\n        public void RecorderAudioDispose()\n        {\n            var audioWriterMock = _moq.GetAudioFileWriterMock();\n            var audioProviderMock = _moq.GetAudioProviderMock();\n\n            using (new AudioRecorder(audioWriterMock.Object, audioProviderMock.Object))\n            {\n            }\n            \n            audioWriterMock.Verify(M => M.Dispose(), Times.Once);\n            audioProviderMock.Verify(M => M.Dispose(), Times.Once);\n        }\n\n        [Fact]\n        public void StartAfterDisposed()\n        {\n            var imageProvider = _moq.GetImageProviderMock().Object;\n            var videoWriter = _moq.GetVideoFileWriterMock().Object;\n\n            var recorder = new Recorder(videoWriter, imageProvider, 10);\n\n            using (recorder)\n            {\n            }\n\n            Assert.Throws<ObjectDisposedException>(() => recorder.Start());\n        }\n\n        [Fact]\n        public void StopAfterDisposed()\n        {\n            var imageProvider = _moq.GetImageProviderMock().Object;\n            var videoWriter = _moq.GetVideoFileWriterMock().Object;\n\n            var recorder = new Recorder(videoWriter, imageProvider, 10);\n\n            using (recorder)\n            {\n            }\n\n            Assert.Throws<ObjectDisposedException>(() => recorder.Stop());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Tests/ScreenShotTests.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.IO;\nusing Xunit;\n\nnamespace Captura.Tests.Views\n{\n    [Collection(nameof(Tests))]\n    public class ScreenShotTests : IClassFixture<AppRunnerFixture>\n    {\n        readonly AppRunnerFixture _appRunner;\n\n        public ScreenShotTests(AppRunnerFixture AppRunner)\n        {\n            _appRunner = AppRunner;\n        }\n\n        static void Shot(string FileName, IntPtr Window)\n        {\n            Thread.Sleep(500);\n\n            var startInfo = new ProcessStartInfo\n            {\n                FileName = TestManagerFixture.GetCliPath(),\n                Arguments = $\"shot --source win:{Window} -f {FileName}\",\n                UseShellExecute = false,\n                CreateNoWindow = true\n            };\n\n            var process = Process.Start(startInfo);\n            process?.WaitForExit();\n\n            Assert.False(process == null || process.ExitCode != 0,\n                $\"Error occurred when taking ScreenShot, hWnd: {Window}, FileName: {FileName}, ExitCode: {process?.ExitCode}\");\n\n            Assert.True(File.Exists(FileName), $\"ScreenShot was not saved: {FileName}\");\n        }\n\n        /// <summary>\n        /// Take ScreenShot of all Tabs.\n        /// </summary>\n        // TODO: Don't skip this test\n        [Fact(Skip = \"This is failing randomly on AppVeyor\")]\n        public void ScreenShotTabs()\n        {\n            Shot(\"shot.png\", _appRunner.App.Process.MainWindowHandle);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Tests/Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <AssemblyName>Captura.Tests</AssemblyName>\n    <TargetFramework>net472</TargetFramework>\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Captura.Base\\Captura.Base.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Core\\Captura.Core.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Fakes\\Captura.Fakes.csproj\" />\n    <ProjectReference Include=\"..\\Captura.Loc\\Captura.Loc.csproj\" />\n    <ProjectReference Include=\"..\\Screna\\Screna.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Moq\" Version=\"4.8.3\" />\n    <PackageReference Include=\"TestStack.White\" Version=\"0.13.3\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"15.3.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.2.0\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.2.0\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Tests/WindowTests.cs",
    "content": "﻿using System;\nusing Xunit;\n\nnamespace Captura.Tests\n{\n    [Collection(nameof(Tests))]\n    public class WindowTests\n    {\n        [Fact]\n        public void ZeroPointerWindow()\n        {\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            Assert.Throws<ArgumentException>(() => platformServices.GetWindow(IntPtr.Zero));\n        }\n\n        [Fact]\n        public void DesktopWindowNotZero()\n        {\n            var platformServices = ServiceProvider.Get<IPlatformServices>();\n\n            Assert.NotEqual(IntPtr.Zero, platformServices.DesktopWindow.Handle);\n        }\n    }\n}\n"
  }
]