[
  {
    "path": ".dockerignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n#*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n**/nupkg/*\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Mockaco-specific\n**/.dockerignore\n**/*.md\n.github/\nnupkg/\ntest/\nwebsite/\n**/*.log\nsrc/Mockaco/Mocks*/**/*.*\n!src/Mockaco/Mocks/hello.json"
  },
  {
    "path": ".editorconfig",
    "content": "[*.{cs,vb}]\ndotnet_naming_rule.private_members_with_underscore.symbols  = private_fields\ndotnet_naming_rule.private_members_with_underscore.style    = prefix_underscore\ndotnet_naming_rule.private_members_with_underscore.severity = suggestion\n\ndotnet_naming_symbols.private_fields.applicable_kinds           = field\ndotnet_naming_symbols.private_fields.applicable_accessibilities = private\n\ndotnet_naming_style.prefix_underscore.capitalization = camel_case\ndotnet_naming_style.prefix_underscore.required_prefix = _"
  },
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/01_feature_request.yml",
    "content": "---\nname: 🚀 Feature request\ndescription: Suggest an idea for this project\nlabels: [\"enhancement\"]\nbody:\n  - type: checkboxes\n    id: prerequisites\n    attributes:\n      label: Prerequisites\n      options:\n        - label: I have written a descriptive issue title\n          required: true\n        - label: I have searched existing issues to ensure a similar issue has not already been created\n          required: true\n\n  - type: textarea\n    id: context\n    attributes:\n      label: Description\n      description: Is your feature request related to a problem? Please describe.\n      placeholder: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n    validations:\n      required: true\n\n  - type: textarea\n    id: proposed_solution\n    attributes:\n      label: Proposed solution\n      description: Describe the solution you'd like.\n      placeholder: A clear and concise description of what you want to happen.\n    validations:\n      required: true\n\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Alternatives\n      description: Describe alternatives you've considered.\n      placeholder: A clear and concise description of any alternative solutions or features you've considered.\n    validations:\n      required: true\n\n  - type: textarea\n    id: additional_context\n    attributes:\n      label: Additional context\n      description: Add any other context or screenshots about the feature request here.\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/02_bug_report.yml",
    "content": "---\nname: 🐛 Bug report\ndescription: Create a report to help us improve\nlabels: [\"bug\"]\nbody:\n  - type: checkboxes\n    id: prerequisites\n    attributes:\n      label: Prerequisites\n      options:\n        - label: I have written a descriptive issue title\n          required: true\n        - label: I have searched existing bugs to ensure a similar bug has not already been created\n          required: true\n\n  - type: textarea\n    id: description\n    attributes:\n      label: Description\n      description: A clear and concise description of what the bug is.\n    validations:\n      required: true\n\n  - type: textarea\n    id: steps_to_reproduce\n    attributes:\n      label: Steps to reproduce\n      description: You can attach the mock reproducing the wrong behavior or even the configuration files you are using.\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected_behavior\n    attributes:\n      label: Expected behavior\n      description: A clear and concise description of what you expected to happen.\n    validations:\n      required: true\n\n  - type: textarea\n    id: screenshots\n    attributes:\n      label: Screenshots\n      description: If applicable, add screenshots to help explain your problem.\n    validations:\n      required: false\n\n  - type: textarea\n    id: additional_context\n    attributes:\n      label: Additional context\n      description: Add any other context about the problem here.\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/pull_request_template.md",
    "content": "*Thank you for your contribution to the Mockaco 🐵 repo!*\n\nBefore submitting this PR, please make sure:\n\n- [ ] There is an open issue related to your change\n- [ ] There aren't other open pull request for the same update/change\n- [ ] You have followed the project guidelines\n- [ ] Your code builds clean without any errors or warnings\n- [ ] You have added unit tests\n\nPlease provide a description of your changes and why you'd like us to include them.\n"
  },
  {
    "path": ".github/workflows/main-release.yml",
    "content": "name: Main Release\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - '**'\n\nenv:\n  DOCKER_HUB_USERNAME: natenho\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    if: \"!contains(github.event.head_commit.message, 'skip-ci')\"\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v1\n        with:\n          fetch-depth: 0\n      - name: Setup .NET\n        uses: actions/setup-dotnet@v1\n        with:\n          dotnet-version: '6.0.x'\n      - name: Setup GitVersion\n        uses: gittools/actions/gitversion/setup@v0.9.7\n        with:\n          versionSpec: '5.x'\n      - name: Determine version\n        id: gitversion\n        uses: gittools/actions/gitversion/execute@v0.9.7\n      - name: Restore dependencies\n        run: dotnet restore --verbosity normal\n      - name: Build\n        run: dotnet build --configuration Release --verbosity normal src/Mockaco/Mockaco.csproj\n      - name: Test\n        run: dotnet test --configuration Release --verbosity normal test/Mockaco.AspNetCore.Tests/Mockaco.AspNetCore.Tests.csproj\n      - name: Bump version and push tag\n        if: \"github.ref == 'refs/heads/master' && !contains(github.event.head_commit.message, 'skip-release')\"\n        id: tag_version\n        uses: mathieudutour/github-tag-action@v5.6\n        with:\n          custom_tag: ${{ steps.gitversion.outputs.semVer }}\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n      - name: Create a GitHub release\n        if: \"github.ref == 'refs/heads/master'\"\n        id: github_release\n        uses: ncipollo/release-action@v1\n        with:\n          tag: v${{ steps.gitversion.outputs.semVer }}\n          name: v${{ steps.gitversion.outputs.semVer }}\n          body: ${{ steps.tag_version.outputs.changelog }}\n      - name: Create nupkg\n        run: dotnet pack --configuration Nuget --output ./nupkg\n      - name: Publish nupkg\n        if: \"github.ref == 'refs/heads/master' && !contains(github.event.head_commit.message, 'skip-nuget')\"\n        run: dotnet nuget push **/*.nupkg --api-key ${{secrets.NUGET_AUTH_TOKEN}} --source https://api.nuget.org/v3/index.json --skip-duplicate\n      - name: Cache Docker layers\n        uses: actions/cache@v4\n        with:\n          path: /tmp/.buildx-cache\n          key: ${{ runner.os }}-buildx-${{ github.sha }}\n          restore-keys: |\n            ${{ runner.os }}-buildx-\n      - name: Login to Docker Hub\n        uses: docker/login-action@v1\n        if: \"github.ref == 'refs/heads/master'\"\n        with:\n          username: ${{ env.DOCKER_HUB_USERNAME }}\n          password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v2\n      - name: Setup Docker Build\n        id: buildx\n        uses: docker/setup-buildx-action@v2\n      - name: Docker Build\n        id: docker_build\n        uses: docker/build-push-action@v2\n        with:\n          context: ./\n          file: ./src/Mockaco/Docker/Dockerfile\n          push: ${{ github.ref == 'refs/heads/master' && !contains(github.event.head_commit.message, 'skip-docker') }}\n          tags: ${{ env.DOCKER_HUB_USERNAME }}/mockaco:latest,${{ env.DOCKER_HUB_USERNAME }}/mockaco:${{ steps.gitversion.outputs.semVer }}\n          cache-from: type=local,src=/tmp/.buildx-cache\n          cache-to: type=local,dest=/tmp/.buildx-cache\n          platforms: linux/amd64,linux/arm64\n      - name: Docker Image digest\n        run: echo ${{ steps.docker_build.outputs.digest }}\n"
  },
  {
    "path": ".github/workflows/website-deploy-test.yml",
    "content": "name: Deploy to GitHub Pages (Test)\n\non:\n  pull_request:\n    branches:\n      - master\n\ndefaults:\n  run:\n    working-directory: ./website\n\njobs:\n  test-deploy:\n    name: Test deployment\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-node@v3\n        with:\n          node-version: 18\n          cache: yarn\n          cache-dependency-path: '**/yarn.lock'\n\n      - name: Install dependencies\n        run: yarn install --frozen-lockfile\n      - name: Test build website\n        run: yarn build"
  },
  {
    "path": ".github/workflows/website-deploy.yml",
    "content": "name: Deploy to GitHub Pages\n\non:\n  push:\n    branches:\n      - master\n    # Review gh actions docs if you want to further define triggers, paths, etc\n    # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on\n\ndefaults:\n  run:\n    working-directory: ./website\n\njobs:\n  deploy:\n    name: Deploy to GitHub Pages\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: actions/setup-node@v3\n        with:\n          node-version: 18\n          cache: yarn\n          cache-dependency-path: '**/yarn.lock'\n\n      - name: Install dependencies\n        run: yarn install --frozen-lockfile\n      - name: Build website\n        run: yarn build\n\n      # Popular action to deploy to GitHub Pages:\n      # Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus\n      - name: Deploy to GitHub Pages\n        uses: peaceiris/actions-gh-pages@v3\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          # Build output to publish to the `gh-pages` branch:\n          publish_dir: ./website/build\n          # The following lines assign commit authorship to the official\n          # GH-Actions bot for deploys to `gh-pages` branch:\n          # https://github.com/actions/checkout/issues/13#issuecomment-724415212\n          # The GH actions bot is used by default if you didn't specify the two fields.\n          # You can swap them out with your own user credentials.\n          user_name: github-actions[bot]\n          user_email: 41898282+github-actions[bot]@users.noreply.github.com"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n#*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n**/nupkg/*\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Mock Files\nsrc/Mockaco/Mocks*/**/*.*\n!src/Mockaco/Mocks/hello.json\n/.vscode\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\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at natenho@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## How to contribute to Mockaco\n\nIt's great you're reading this, because we need volunteer developers to help this project to move on!\n\nPlease take care of reading existent code to follow the same conventions and use clean code intentions when writing new code. Consider the people who will read your code, and make it look nice for them :-).\n\n#### **Did you find a bug?**\n\n* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/natenho/mockaco/issues).\n\n* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/natenho/mockaco/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **mock template** or an **executable test case** demonstrating the expected behavior that is not occurring.\n\n#### **Did you write a patch that fixes a bug?**\n\n* Open a new GitHub pull request with the patch.\n\n* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.\n\n#### **Do you intend to add a new feature or change an existing one?**\n\n* Please [open a new issue](https://github.com/natenho/mockaco/issues/new) describing the feature so it can be discussed before you start writing it.\n\n#### **Do you have any other questions?**\n\n* Simply [open a new issue](https://github.com/natenho/mockaco/issues/new).\n\nThanks!\n\nMockaco Team 🐵\n\n"
  },
  {
    "path": "LICENSE",
    "content": "   Mockaco - Copyright (c) 2019-2021 Renato Lima\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this source code except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n   \n   --\n   \n   Serilog is copyright © 2013-2020 Serilog Contributors   \n   All Rights Reserved\n   \n   xUnit Copyright (c) .NET Foundation and Contributors\n   All Rights Reserved\n   \n   Fluent Assertions © 2021 Dennis Doomen      \n   \n   --\n   \n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS   \n\n   --\n  \n   The MIT License (MIT)\n   \n   MAB.DotIgnore - Copyright (c) 2016 Mark Ashley Bell\n   Bogus - Copyright (c) 2015 Brian Chavez\n   GitVersion - Copyright (c) 2013 NServiceBus Ltd\n   Moq - Copyright (c) Daniel Cazzulino and Contributors\n   Newtonsoft.Json - Copyright (c) 2007 James Newton-King\n   \n   Permission 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   \n   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n   \n   THE 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.\n   \n   --\n        \n   New BSD License\n   \n   Polly - Copyright (c) 2015-2020, App vNext   \n   All rights reserved.\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are met:\n       * Redistributions of source code must retain the above copyright\n         notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above copyright\n         notice, this list of conditions and the following disclaimer in the\n         documentation and/or other materials provided with the distribution.\n       * Neither the name of App vNext nor the\n         names of its contributors may be used to endorse or promote products\n         derived from this software without specific prior written permission.\n   \n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n   DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\n   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "Mockaco.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.1.32210.238\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Mockaco\", \"src\\Mockaco\\Mockaco.csproj\", \"{8BAA1EC5-0BF5-4DA2-87F7-ED0C7B652517}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{3F7B6722-59F1-4943-8D45-94D42CE49639}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tREADME.md = README.md\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Mockaco.AspNetCore.Tests\", \"test\\Mockaco.AspNetCore.Tests\\Mockaco.AspNetCore.Tests.csproj\", \"{EE57B1B4-29D2-4AE3-8F23-5E622302C30F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Mockaco.AspNetCore\", \"src\\Mockaco.AspNetCore\\Mockaco.AspNetCore.csproj\", \"{7766C592-9887-4162-8B9C-51003ED30335}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tNuget|Any CPU = Nuget|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{8BAA1EC5-0BF5-4DA2-87F7-ED0C7B652517}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8BAA1EC5-0BF5-4DA2-87F7-ED0C7B652517}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8BAA1EC5-0BF5-4DA2-87F7-ED0C7B652517}.Nuget|Any CPU.ActiveCfg = Nuget|Any CPU\n\t\t{8BAA1EC5-0BF5-4DA2-87F7-ED0C7B652517}.Nuget|Any CPU.Build.0 = Nuget|Any CPU\n\t\t{8BAA1EC5-0BF5-4DA2-87F7-ED0C7B652517}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8BAA1EC5-0BF5-4DA2-87F7-ED0C7B652517}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{EE57B1B4-29D2-4AE3-8F23-5E622302C30F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{EE57B1B4-29D2-4AE3-8F23-5E622302C30F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{EE57B1B4-29D2-4AE3-8F23-5E622302C30F}.Nuget|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{EE57B1B4-29D2-4AE3-8F23-5E622302C30F}.Release|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7766C592-9887-4162-8B9C-51003ED30335}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7766C592-9887-4162-8B9C-51003ED30335}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7766C592-9887-4162-8B9C-51003ED30335}.Nuget|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7766C592-9887-4162-8B9C-51003ED30335}.Nuget|Any CPU.Build.0 = Release|Any CPU\n\t\t{7766C592-9887-4162-8B9C-51003ED30335}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7766C592-9887-4162-8B9C-51003ED30335}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {CABB6019-182D-4F69-834A-5CF7921C290F}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n    <img src=\"https://github.com/natenho/Mockaco/raw/master/src/Mockaco/Resources/mockaco-logo.svg\" width=\"96px\" height=\"96px\" alt=\"Mockaco\">\n</p>\n\n# Mockaco\n\n[![Main Build](https://github.com/natenho/Mockaco/actions/workflows/main-release.yml/badge.svg)](https://github.com/natenho/Mockaco/actions/workflows/main-release.yml) [![Docker Pulls](https://img.shields.io/docker/pulls/natenho/mockaco)](https://hub.docker.com/repository/docker/natenho/mockaco) [![Nuget](https://img.shields.io/nuget/dt/Mockaco?color=blue&label=nuget%20downloads)](https://www.nuget.org/packages/Mockaco/) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fnatenho%2FMockaco.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fnatenho%2FMockaco?ref=badge_shield)\n\nMockaco is an HTTP-based API mock server with fast setup.\n\n## Features\n\n- **Simple JSON-based Configuration**: Configure your mocks easily using a simple JSON format.\n- **Pure C# Scripting**: Configure your mocks using C# scripting without the need to learn a new language or API.\n- **Delay Simulation**: Simulate network delays to test how your system handles timeouts and latency.\n- **Fake Data Generation**: Generate realistic fake data using the built-in functionality.\n- **Callback (Webhook) Support**: Trigger another service call when a request hits your mocked API.\n- **Verification**: Verify if a specific mock was called during testing to ensure expected interactions.\n- **State Support**: Create stateful mocks that return responses based on global variables previously set by other mocks.\n- **Portability**: Run the mock server in [any environment supported by .NET](https://github.com/dotnet/core/blob/main/release-notes/6.0/supported-os.md).\n\n## Get Started\n\nAccess the documentation on <strong>[natenho.github.io/Mockaco](https://natenho.github.io/Mockaco/)</strong>\n\n[![Mocking APIs with Mockaco | .NET 7](https://user-images.githubusercontent.com/4236481/195997781-b730959e-8d6d-432c-b35a-3adb580abc41.png)](https://www.youtube.com/watch?v=QBnXCgZFzM0 \"Mocking APIs with Mockaco | .NET 7\")\n\n## License\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fnatenho%2FMockaco.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fnatenho%2FMockaco?ref=badge_large)\n\n---\n\n*Icon made by [Freepik](https://www.freepik.com/ \"Freepik\") from [www.flaticon.com](https://www.flaticon.com/ \"Flaticon\") is licensed by [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/ \"Creative Commons BY 3.0\")*\n\n"
  },
  {
    "path": "appveyor.yml",
    "content": "pull_requests:\n  do_not_increment_build_number: true\nskip_non_tags: true\nimage: Visual Studio 2019\nconfiguration: Release\ndotnet_csproj:\n  patch: true\n  file: '**\\*.csproj'\n  version: '{version}'\n  version_prefix: '{version}'\n  package_version: '{version}'\n  assembly_version: '{version}'\n  file_version: '{version}'\n  informational_version: '{version}'\nbuild_script:\n- cmd: >-\n    dotnet --version\n    dotnet restore ./src/Mockaco/Mockaco.csproj --verbosity m\n    dotnet publish ./src/Mockaco/Mockaco.csproj\ntest_script:\n- cmd: dotnet test .\\test\\Mockaco.AspNetCore.Tests\\Mockaco.AspNetCore.Tests.csproj\nartifacts:\n- path: src\\Mockaco\\bin\\Release\\net5.0\\publish\\\n  name: Mockaco Web Site\ndeploy:\n- provider: GitHub\n  tag: v$(appveyor_build_version)\n  auth_token:\n    secure: ksH+zrtlbEnpy6gasfUkZJQrewTVWVKVFPbzTDmhH94Q2SVBMEc4pI6+6I8JaGuE\n  artifact: Mockaco Web Site\n  draft: false\n  force_update: true\n  on:\n    APPVEYOR_REPO_TAG: true\n- provider: NuGet\n  api_key:\n    secure: DPYxpk2NINisxfFbRST6aH/m0KBYAt9ETmwkMgxRaGqnKtWlFKaZZFuqXtAG4eSj\n  on:\n    APPVEYOR_REPO_TAG: true"
  },
  {
    "path": "checkBuild.ps1",
    "content": "dotnet restore --verbosity normal\ndotnet build --configuration Release --verbosity normal .\\src\\Mockaco\\Mockaco.csproj\ndotnet test --configuration Release --verbosity normal .\\test\\Mockaco.AspNetCore.Tests\\Mockaco.AspNetCore.Tests.csproj\ndotnet pack --configuration Nuget --output ./nupkg\ndocker build -f ./src/Mockaco/Docker/Dockerfile -t mockaco:local .\n\n$containerName = [guid]::NewGuid().ToString()\ntry {\n    docker run --name $containerName -d -p 5000:5000 -v ${PSScriptRoot}/src/Mockaco/Mocks:/app/Mocks mockaco:local\n    Start-Sleep -Seconds 5\n    docker run --rm -v ${PSScriptRoot}/test/_postman:/etc/newman -t postman/newman:alpine run Mockaco.postman_collection.json\n}\nfinally {\n    docker container stop $containerName\n    docker container rm $containerName\n}\n"
  },
  {
    "path": "src/Mockaco/.dockerignore",
    "content": "**/.classpath\n**/.dockerignore\n**/.env\n**/.git\n**/.gitignore\n**/.project\n**/.settings\n**/.toolstarget\n**/.vs\n**/.vscode\n**/*.*proj.user\n**/*.dbmdl\n**/*.jfm\n**/azds.yaml\n**/bin\n**/charts\n**/docker-compose*\n**/Dockerfile*\n**/node_modules\n**/npm-debug.log\n**/obj\n**/secrets.dev.yaml\n**/values.dev.yaml\nLICENSE\nREADME.md\n/Mocks/*.json\n!/Mocks/hello.json"
  },
  {
    "path": "src/Mockaco/Docker/Dockerfile",
    "content": "FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base\nWORKDIR /app\nEXPOSE 5000\nEXPOSE 5443\n\nFROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim AS build\n\nCOPY ./src/Mockaco/Mockaco.csproj /src/Mockaco/\nCOPY ./src/Mockaco.AspNetCore/Mockaco.AspNetCore.csproj /src/Mockaco.AspNetCore/\n\nWORKDIR /src/Mockaco\nRUN dotnet restore\n\nWORKDIR /repo\nCOPY ./ ./\n\nWORKDIR /repo/src/Mockaco\nRUN dotnet build \"Mockaco.csproj\" -c Release -o /app/build\nRUN find -iname gitversion.json -exec cat {} \\;\nRUN dotnet dev-certs https\n\nFROM build AS publish\nRUN dotnet publish \"Mockaco.csproj\" -c Release -o /app/publish\n\nFROM base AS final\nENV DOTNET_USE_POLLING_FILE_WATCHER=true\nENV ASPNETCORE_ENVIRONMENT=Docker\nWORKDIR /app\n\nCOPY --from=publish /app/publish .\nCOPY ./src/Mockaco/Mocks/hello.json ./Mocks/\nCOPY ./src/Mockaco/Settings ./Settings\n\nCOPY --from=build /root/.dotnet/corefx/cryptography/x509stores/my /root/.dotnet/corefx/cryptography/x509stores/my\n\nVOLUME /app/Mocks\nVOLUME /app/Settings\nVOLUME /root/.dotnet/corefx/cryptography/x509stores/my\n\nENTRYPOINT [\"dotnet\", \"Mockaco.dll\"]"
  },
  {
    "path": "src/Mockaco/Docker/README.md",
    "content": "# Quick reference\n\n-\t**Where to get help and to file issues**:  \n\t[GitHub repository](https://github.com/natenho/Mockaco/)\n\n-\t**Maintained by**:  \n\t[natenho](https://github.com/natenho)\n\n# What is Mockaco?\n\nMockaco is an HTTP-based API mock server with fast setup, featuring:\n\n- Simple JSON-based configuration\n- Pure C# scripting - you don't need to learn a new specific language or API to configure your mocks\n- Fake data generation - built-in hassle-free fake data generation\n- Callback support - trigger another service call when a request hits your mocked API\n\n<img src=\"https://image.flaticon.com/icons/svg/1574/1574279.svg\" width=\"100px\" height=\"100px\" alt=\"logo\">\n\n# How to use this image\n\n## Running the demo\n\nThe default image ships with a sample \"hello\" mock:\n\n```console\n$ docker run -it --rm -p 5000:5000 natenho/mockaco\n```\n\nMockaco can be accessed by any HTTP client via `http://localhost:5000`\n\n```console\n$ curl -iX GET http://localhost:5000/hello/docker\n```\n```http\nHTTP/1.1 200 OK\nDate: Wed, 21 Jun 2019 05:10:00 GMT\nContent-Type: application/json\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\n\t\"message\": \"Hello docker!\"\n}\n```\n\n## Running and creating your own mocks\n\nThe best way to use the image is by creating a directory on the host system (outside the container) and mount this to the `/app/Mocks` directory inside the container.\n\n1. Create a data directory on a suitable volume on your host system, e.g. `/my/own/mockdir`.\n2. Start your `mockaco` container like this:\n\n```console\n$ docker run -it --rm -p 5000:80 -v /my/own/mockdir:/app/Mocks natenho/mockaco\n```\n\nThe `-v /my/own/mockdir:/app/Mocks` part of the command mounts the `/my/own/mockdir` directory from the underlying host system as `/app/Mocks` inside the container, where Mockaco by default will read its mock JSON files.\n\n3. Create a request/response template file named `PingPong.json` under `/my/own/mockdir` folder:\n\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\",\n\t\"route\": \"ping\"\n  },\n  \"response\": {\n\t\"status\": \"OK\",\n\t\"body\": {\n\t  \"response\": \"pong\"\n\t}\n  }\n}\n```\n\n4. Send a request and get the mocked response, running:\n\n```console\n$ curl -iX GET http://localhost:5000/ping\n```\n```http\nHTTP/1.1 200 OK\nDate: Wed, 21 Jun 2019 05:10:00 GMT\nContent-Type: application/json\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\n\t\"response\": \"pong\"\n}\n```\n\nFor advanced usage scenarios, like scripting and fake data generation, refer to the [docs](https://github.com/natenho/Mockaco)."
  },
  {
    "path": "src/Mockaco/Extensions/CommandLineExtensions.cs",
    "content": "﻿namespace System.CommandLine.Parsing\n{\n    public static class CommandLineExtensions\n    {\n        public static bool IsUsingCommand(this Parser commandLine, string[] args)\n        {\n            var parseResult = commandLine.Parse(args);\n\n            return parseResult.CommandResult != parseResult.RootCommandResult;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco/Mockaco.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net6.0</TargetFramework>\n\t\t<LangVersion>latest</LangVersion>\n\t\t<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>\n\t\t<DockerfileContext>..\\..</DockerfileContext>\n\t\t<SatelliteResourceLanguages>en</SatelliteResourceLanguages>\n\t\t<Configurations>Debug;Release;Nuget</Configurations>\n\t</PropertyGroup>\n\n\t<PropertyGroup>\n\t\t<IsPackable>true</IsPackable>\n\t\t<PackAsTool>true</PackAsTool>\n\t\t<ToolCommandName>mockaco</ToolCommandName>\n\t\t<PackageOutputPath>./nupkg</PackageOutputPath>\n\t\t<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>\n\t\t<Authors>natenho</Authors>\n\t\t<Description>HTTP mock server, useful to stub services and simulate dynamic API responses, leveraging ASP.NET Core features, built-in fake data generation and pure C# scripting</Description>\n\t\t<PackageProjectUrl>https://github.com/natenho/Mockaco</PackageProjectUrl>\n\t\t<RepositoryUrl>https://github.com/natenho/Mockaco</RepositoryUrl>\n\t\t<PackageTags>mock http server</PackageTags>\n\t\t<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>\n\t\t<PackageIcon>mockaco-icon.png</PackageIcon>\n\t\t<Product>Mockaco</Product>\n\t</PropertyGroup>\n\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n\t\t<TreatWarningsAsErrors>True</TreatWarningsAsErrors>\n\t\t<WarningsNotAsErrors></WarningsNotAsErrors>\n\t\t<NoWarn>1701;1702;NU5104</NoWarn>\n\t</PropertyGroup>\n\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|AnyCPU'\">\n\t\t<TreatWarningsAsErrors>True</TreatWarningsAsErrors>\n\t\t<WarningsNotAsErrors></WarningsNotAsErrors>\n\t\t<NoWarn>1701;1702;NU5104</NoWarn>\n\t</PropertyGroup>\n\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Nuget|AnyCPU'\">\n\t\t<TreatWarningsAsErrors>True</TreatWarningsAsErrors>\n\t\t<WarningsNotAsErrors></WarningsNotAsErrors>\n\t\t<NoWarn>1701;1702;NU5104</NoWarn>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n\t\t<PackageReference Include=\"GitVersion.MsBuild\" Version=\"5.12.0\">\n\t\t\t<PrivateAssets>all</PrivateAssets>\n\t\t\t<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n\t\t</PackageReference>\n\t\t<PackageReference Include=\"Microsoft.Extensions.FileProviders.Physical\" Version=\"6.0.0\" />\n\t\t<PackageReference Include=\"Microsoft.VisualStudio.Azure.Containers.Tools.Targets\" Version=\"1.18.1\" />\n\t\t<PackageReference Include=\"Serilog.AspNetCore\" Version=\"7.0.0\" />\n\t\t<PackageReference Include=\"Serilog.Settings.Configuration\" Version=\"7.0.0\" />\n\t\t<PackageReference Include=\"Serilog.Sinks.Console\" Version=\"4.1.0\" />\n\t\t<PackageReference Include=\"Serilog.Sinks.File\" Version=\"5.0.0\" />\n\t\t<PackageReference Include=\"System.CommandLine\" Version=\"2.0.0-beta1.21308.1\" />\n\t</ItemGroup>\n\n\t<ItemGroup Condition=\"$(Configuration) != 'Debug'\">\n\t\t<Content Remove=\"Mocks\\**\" />\n\t\t<None Include=\"Mocks\\hello.json\">\n\t\t\t<CopyToOutputDirectory>Always</CopyToOutputDirectory>\n\t\t</None>\n\t\t<None Include=\"Resources\\mockaco-icon.png\">\n\t\t\t<Pack>True</Pack>\n\t\t\t<PackagePath></PackagePath>\n\t\t</None>\n\t\t<Content Remove=\"Settings\\**\" />\n\t\t<None Include=\"Settings\\**\">\n\t\t\t<CopyToOutputDirectory>Always</CopyToOutputDirectory>\n\t\t</None>\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<ProjectReference Include=\"..\\Mockaco.AspNetCore\\Mockaco.AspNetCore.csproj\" />\n\t</ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Mockaco/Mocks/hello.json",
    "content": "{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"hello/{message}\"\n  },\n  \"response\": {\n    \"body\": {\n\t\t\"id\": \"<#= Faker.Random.Guid() #>\",\n\t\t\"message\": \"Hello <#= Request.Route[\"message\"] #>!\",\n\t\t\"createdAt\": <#= JsonConvert.SerializeObject(System.DateTime.Now) #>\n\t  }\n  }\n}"
  },
  {
    "path": "src/Mockaco/Program.cs",
    "content": "﻿using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Serilog;\nusing System.Collections.Generic;\nusing System.CommandLine;\nusing System.CommandLine.Builder;\nusing System.CommandLine.Parsing;\nusing System.IO;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection; \n\nnamespace Mockaco\n{\n    public class Program\n    {\n        public static async Task Main(string[] args)\n        {\n            var host = CreateHostBuilder(args).Build();\n\n            var commandLine = CreateCommandLineBuilder(args, host)\n                .UseDefaults()\n                .Build();\n\n            if (commandLine.IsUsingCommand(args))\n            {\n                await commandLine.InvokeAsync(args);\n                return;\n            }\n\n            await host.RunAsync();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.ConfigureAppConfiguration((_, configuration) =>\n                    {\n                        var assemblyLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n                        configuration.SetBasePath(Path.Combine(assemblyLocation, \"Settings\"));\n\n                        var switchMappings = new Dictionary<string, string>() {\n                            {\"--path\", \"Mockaco:TemplateFileProvider:Path\" },\n                            {\"--logs\", \"Serilog:WriteTo:0:Args:path\" }\n                        };\n\n                        configuration.AddCommandLine(args, switchMappings);\n                    })\n                    .UseStartup<Startup>();\n                })\n            .UseSerilog((context, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(context.Configuration));\n\n        private static CommandLineBuilder CreateCommandLineBuilder(string[] args, IHost host)\n        {\n            var rootCommand = new RootCommand();\n\n            foreach (var cmd in host.Services.GetServices<Command>())\n            {\n                rootCommand.AddCommand(cmd);\n            }\n\n            return new CommandLineBuilder(rootCommand);\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco/Properties/PublishProfiles/FolderProfile.pubxml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nThis file is used by the publish/package process of your Web project. You can customize the behavior of this process\nby editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. \n-->\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <WebPublishMethod>FileSystem</WebPublishMethod>\n    <PublishProvider>FileSystem</PublishProvider>\n    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>\n    <LastUsedPlatform>Any CPU</LastUsedPlatform>\n    <SiteUrlToLaunchAfterPublish />\n    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>\n    <ExcludeApp_Data>False</ExcludeApp_Data>\n    <ProjectGuid>8baa1ec5-0bf5-4da2-87f7-ed0c7b652517</ProjectGuid>\n    <publishUrl>publish</publishUrl>\n    <DeleteExistingFiles>True</DeleteExistingFiles>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "src/Mockaco/Properties/launchSettings.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/launchsettings.json\",\n  \"profiles\": {\n    \"Mockaco\": {\n      \"commandName\": \"Project\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      },\n      \"applicationUrl\": \"http://localhost:5000\"\n    }\n  }\n}"
  },
  {
    "path": "src/Mockaco/Settings/appsettings.Development.json",
    "content": "{\n  \"Mockaco\": {\n    \"TemplateFileProvider\": {\n      \"Path\": \"Mocks\"\n    }\n  },\n  \"Serilog\": {\n    \"WriteTo\": [\n      {\n      },\n      {\n        \"Name\": \"File\",\n        \"Args\": {\n          \"path\": \"Logs/Mockaco_.log\",\n          \"rollingInterval\": \"Day\",\n          \"outputTemplate\": \"[{Timestamp:HH:mm:ss} {Level:u3}] {RequestId} {Message:lj}{NewLine}{Exception}\"\n        }\n      }\n    ]\n  }\n}"
  },
  {
    "path": "src/Mockaco/Settings/appsettings.Docker.json",
    "content": "{\n  \"Urls\": \"http://+:5000;https://+:5443\",\n  \"Mockaco\": {\n    \"TemplateFileProvider\": {\n      \"Path\": \"Mocks\"\n    }\n  }\n}"
  },
  {
    "path": "src/Mockaco/Settings/appsettings.Production.json",
    "content": "{\n  \"Urls\": \"http://127.0.0.1:0\",\n  \"Serilog\": {\n    \"WriteTo\": [\n      {\n      },\n      {\n        \"Name\": \"File\",\n        \"Args\": {\n          \"path\": \"Logs/Mockaco_.log\",\n          \"rollingInterval\": \"Day\",\n          \"outputTemplate\": \"[{Timestamp:HH:mm:ss} {Level:u3}] {RequestId} {Message:lj}{NewLine}{Exception}\"\n        }\n      }\n    ]\n  }\n}"
  },
  {
    "path": "src/Mockaco/Settings/appsettings.json",
    "content": "{\n  \"Mockaco\": {\n    \"DefaultHttpStatusCode\": \"OK\",\n    \"ErrorHttpStatusCode\": \"NotImplemented\",\n    \"DefaultHttpContentType\": \"application/json\",\n    \"References\": [],\n    \"VerificationIgnoredHeaders\": [\n        \"Accept\",\n        \"Connection\",\n        \"Host\",\n        \"User-Agent\",\n        \"Accept-Encoding\",\n        \"Postman-Token\",\n        \"Content-Type\",\n        \"Content-Length\"\n    ],\n    \"Imports\": [],\n    \"MatchedRoutesCacheDuration\": 60,\n    \"MockacoEndpoint\": \"_mockaco\",\n    \"VerificationEndpointName\": \"verification\",\n    \"Chaos\": {\n      \"Enabled\": false,\n      \"ChaosRate\": 20,\n      \"MinimumLatencyTime\": 500,\n      \"MaximumLatencyTime\": 3000,\n      \"TimeBeforeTimeout\": 10000\n    }\n  },\n  \"AllowedHosts\": \"*\",\n  \"Serilog\": {\n    \"MinimumLevel\": {\n      \"Default\": \"Debug\",\n      \"Override\": {\n        \"Microsoft\": \"Information\",\n        \"System\": \"Information\"\n      }\n    },\n    \"WriteTo\": [\n      {\n        \"Name\": \"Console\",\n        \"Args\": {\n          \"theme\": \"Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Literate, Serilog.Sinks.Console\",\n          \"outputTemplate\": \"[{Timestamp:HH:mm:ss} {Level:u3}] {RequestId} {Message:lj}{NewLine}{Exception}\"\n        }\n      }\n    ]\n  }\n}"
  },
  {
    "path": "src/Mockaco/Startup.Banner.cs",
    "content": "﻿namespace Mockaco\n{\n    public partial class Startup\n    {\n        private const string _logo =\n        \"                                            .x000000000000000000000d.          \\n\" +\n        \"                                          .kMW0OkdooooooooooooooookNWd.        \\n\" +\n        \"                          ...           .kMNOdoc;;;;;;;;;;;;;;;;;;;:xNWx.      \\n\" +\n        \"                        lNMWM0'        kMNOdoc;;;;;;;;;;;;;;;;;;;;;;;:xNWl     \\n\" +\n        \"                       .MMo;OMx    :xxkWM0ddlcOKKKKKKKKKKKKKKKKKKKOc;;;kMNxxx: \\n\" +\n        \"                       .MMc;kMx   XMOloWM0ddKWNdllcccccccccccccccdNWx;;kMXoo0MO\\n\" +\n        \"                       .MMc;kMx  .WMc..XM0ddNMd......   .   ......dM0;;kMO..lMK\\n\" +\n        \"                       oMWc;kMx  .WMc..XM0ddNMd......   .   ......dM0;;kMO..lMK\\n\" +\n        \"      cOOOOOOOOOOOOOOONWOc;oXMo  .WMl..XM0ddXMK:,,'..............:KMO;;kMO..oMK\\n\" +\n        \"    lNMKOOxddddddddddddc;dXMO'    lXWNNMM0ddodXWWWMMx.......0MMWWWXo;;;kMWNNWX;\\n\" +\n        \"  lNWKxdkOkkkkkkkkkkkkkOXWk'        ..'NM0ddl;;:::0Mk.......0MO:::;;;;;kM0...  \\n\" +\n        \" NMXxdkXM0ddddddddddddddo.             XM0ddl;;;;;OMk.......0MO;;;;;;;;kMO     \\n\" +\n        \" WMOdOMN,        .,,,,,,,,,,,,,,,,,,   OMNkdo:;;;;dWWkoolllkWNd;;;;;;:dXMd     \\n\" +\n        \" WMOdOMK       ;0MNXXXXXXXXXXXXXXXXX:'''oXMXkdo:;;;:kKKKKKKKx:;;;;;:dXMO,      \\n\" +\n        \" WMOdOMK    .lXW0l;;;;;;;;;;;;;;;;;;;;;;;;oXMNOkxllllllllllllllllldXMk.        \\n\" +\n        \" WMOdOMK  .dWNOc;;;;;;;;;;;;;;;;;;;;;;;;;;;;oK000000000000000000000k.          \\n\" +\n        \" WMOdOMK .WMk:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;.                \\n\" +\n        \" WMOdkWWdoMN:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;lOl               \\n\" +\n        \" kWW0xdONMM0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;xM0               \\n\" +\n        \"  .dWWKxdkXx;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;xM0               \\n\" +\n        \"    .dNWKxdl:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;xM0               \\n\" +\n        \"       oNWKdol:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;lKMk               \\n\" +\n        \"        oMXddd:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cOMWl                \\n\" +\n        \"        OMKddo;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:kWW0xc                \\n\" +\n        \"        NMOddl;;;;;loooooooooooooooooooooooo:;;;;;;;;loxNMKxdloXK              \\n\" +\n        \"       'MMkddc;;;;oWWKNNNNXXXXXXK000000000WMd;;;;;;;;KMWXxo::;;0MO             \\n\" +\n        \"       cMWddd:;;;lWMc.odddc;;;;;.         kMk;;;;;;;cWMkddo:;;;:KMx            \\n\" +\n        \"       dMXddo;;;:KMx  :dddl;;;;x0c        lMK;;;;;;;dMX:dddo:;;;cNMl           \\n\" +\n        \"       0M0ddo;;;OMO  cNXddd:;;;OMk        ;MN:;;;;;;OMk ;dddo:;;;oWW,          \\n\" +\n        \"       NMOddl;;xMX.  'MWxddl;;;OMk        .MMl;;;;;;XMl .xOddo:;;;oWN.         \\n\" +\n        \"      ,MWxddc;lWW'    OM0ddo;;;OMk         NMd;;;;;lMM, .XMKddo;;;;kM0         \\n\" +\n        \"      lMNkkkooNMl     cMNkkkollKMO         0MOlllllkMW.  .KM0kkxllloXMk.       \\n\" +\n        \"      kMWNNNNNNWNl    .NMWNNNNNNNWNo.      xMWNNNNNNNWNo. .KMMNNNNNNNNNMK;     \\n\" +\n        \"      XMl......'dNNc   kMx.......'dNNc     oMK........dNNc .NMd........;OMX'   \\n\" +\n        \"     'MM0OOkkkkkkXM0   :MNOOOkkkkkkKM0     :MWOOOkkkkkkKMO  .XWOOOkkkkkkkWMl   \\n\" +\n        \"     :WWWWWWWWWWWWWO   .WWWWWWWWWWWWWO     ,WWWWWWWWWWWWWk   ;WWWWWWWWWWWWWc   \\n\";\n    }\n}\n"
  },
  {
    "path": "src/Mockaco/Startup.cs",
    "content": "﻿using Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing System.Reflection;\nusing System;\nusing System.Linq;\n\nnamespace Mockaco\n{\n    public partial class Startup\n    {\n        private readonly IConfiguration _configuration;\n\n        public Startup(IConfiguration configuration)\n        {\n            _configuration = configuration;\n        }\n\n        public void ConfigureServices(IServiceCollection services)\n        {\n            services\n                .AddCors()\n                .AddMockaco(_configuration.GetSection(\"Mockaco\"));\n        }\n\n        public void Configure(IApplicationBuilder app, ILogger<Startup> logger)\n        {\n            var assemblyName = Assembly.GetExecutingAssembly().GetName().Name;\n            var version = GitVersionInformation.InformationalVersion;\n            var isNoLogoPassed = Environment.GetCommandLineArgs().Contains(\"--no-logo\");\n\n            var logMessage = \"{assemblyName} v{assemblyVersion} [github.com/natenho/Mockaco]\";\n\n            if (!isNoLogoPassed)\n                logMessage += \"\\n\\n{logo}\";\n\n            logger.LogInformation(logMessage, assemblyName, version, _logo);\n\n            app\n                .UseCors()\n                .UseMockaco();\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Chaos/Strategies/ChaosStrategyBehavior.cs",
    "content": "using System.Net;\nusing System.Text;\nusing Microsoft.AspNetCore.Http;\n\nnamespace Mockaco.Chaos.Strategies;\n\ninternal class ChaosStrategyBehavior : IChaosStrategy\n{\n    public Task Response(HttpResponse httpResponse)\n    {\n        httpResponse.StatusCode = (int)HttpStatusCode.ServiceUnavailable;\n\n        var bodyBytes = Encoding.UTF8.GetBytes($\"Error {httpResponse.StatusCode}: {HttpStatusCode.ServiceUnavailable}\");\n\n        return httpResponse.Body.WriteAsync(bodyBytes, 0, bodyBytes.Length, default);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Chaos/Strategies/ChaosStrategyException.cs",
    "content": "using System.Net;\nusing System.Text;\nusing Microsoft.AspNetCore.Http;\n\nnamespace Mockaco.Chaos.Strategies;\n\ninternal class ChaosStrategyException : IChaosStrategy\n{\n    public Task Response(HttpResponse httpResponse)\n    {\n        httpResponse.StatusCode = (int)HttpStatusCode.InternalServerError;\n\n        var bodyBytes = Encoding.UTF8.GetBytes($\"Error {httpResponse.StatusCode}: {HttpStatusCode.InternalServerError}\");\n\n        return httpResponse.Body.WriteAsync(bodyBytes, 0, bodyBytes.Length);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Chaos/Strategies/ChaosStrategyLatency.cs",
    "content": "using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace Mockaco.Chaos.Strategies;\n\ninternal class ChaosStrategyLatency : IChaosStrategy\n{\n    private readonly ILogger<ChaosStrategyLatency> _logger;\n    private readonly IOptions<ChaosOptions> _options;\n\n    public ChaosStrategyLatency(ILogger<ChaosStrategyLatency> logger, IOptions<ChaosOptions> options)\n    {\n        _logger = logger;\n        _options = options;\n    }\n    public Task Response(HttpResponse httpResponse)\n    {\n        var responseDelay = new Random().Next(_options.Value.MinimumLatencyTime, _options.Value.MaximumLatencyTime);\n        _logger.LogInformation($\"Chaos Latency (ms): {responseDelay}\");\n        return Task.Delay(responseDelay);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Chaos/Strategies/ChaosStrategyResult.cs",
    "content": "using System.Net;\nusing System.Text;\nusing Microsoft.AspNetCore.Http;\n\nnamespace Mockaco.Chaos.Strategies;\n\ninternal class ChaosStrategyResult : IChaosStrategy\n{\n    public Task Response(HttpResponse httpResponse)\n    {\n        httpResponse.StatusCode = (int)HttpStatusCode.BadRequest;\n\n        var bodyBytes = Encoding.UTF8.GetBytes($\"Error {httpResponse.StatusCode}: {HttpStatusCode.BadRequest}\");\n\n        return httpResponse.Body.WriteAsync(bodyBytes, 0, bodyBytes.Length);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Chaos/Strategies/ChaosStrategyTimeout.cs",
    "content": "using System.Net;\nusing System.Text;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Options;\n\nnamespace Mockaco.Chaos.Strategies;\n\ninternal class ChaosStrategyTimeout : IChaosStrategy\n{\n    private readonly IOptions<ChaosOptions> _options;\n\n    public ChaosStrategyTimeout(IOptions<ChaosOptions> options)\n    {\n        _options = options;\n    }\n    \n    public async Task Response(HttpResponse httpResponse)\n    {\n        await Task.Delay(_options.Value.TimeBeforeTimeout);\n\n        httpResponse.StatusCode = (int)HttpStatusCode.RequestTimeout;\n\n        var bodyBytes = Encoding.UTF8.GetBytes($\"Error {httpResponse.StatusCode}: {HttpStatusCode.RequestTimeout}\");\n\n        await httpResponse.Body.WriteAsync(bodyBytes, 0, bodyBytes.Length, default);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Chaos/Strategies/IChaosStrategy.cs",
    "content": "using Microsoft.AspNetCore.Http;\n\nnamespace Mockaco.Chaos.Strategies;\n\ninternal interface IChaosStrategy\n{\n    Task Response(HttpResponse httpResponse);\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Common/HttpContentTypes.cs",
    "content": "﻿namespace Mockaco\n{\n    internal static class HttpContentTypes\n    {\n        public const string ApplicationOctetStream = \"application/octet-stream\";\n        public const string ApplicationJson = \"application/json\";\n        public const string ApplicationXml = \"application/xml\";\n        public const string TextXml = \"text/xml\";\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Common/HttpHeaders.cs",
    "content": "﻿namespace Mockaco\n{\n    internal static class HttpHeaders\n    {\n        public const string ContentType = \"Content-Type\";\n        public const string AcceptLanguage = \"Accept-Language\";\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Common/InvalidMockException.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.Serialization;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Mockaco.Common\n{\n    internal class InvalidMockException : Exception\n    {\n        public InvalidMockException() : base() { }\n\n        public InvalidMockException(string message) : base(message)\n        {\n        }\n\n        public InvalidMockException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n        protected InvalidMockException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Common/RouteMatcher.cs",
    "content": "﻿using Microsoft.AspNetCore.Routing;\nusing Microsoft.AspNetCore.Routing.Template;\n\nnamespace Mockaco\n{\n    internal class RouteMatcher\n    {\n        public RouteValueDictionary Match(string routeTemplate, string requestPath)\n        {\n            if(string.IsNullOrWhiteSpace(routeTemplate))\n            {\n                return null;\n            }\n\n            var template = TemplateParser.Parse(routeTemplate);\n\n            var matcher = new TemplateMatcher(template, GetDefaults(template));\n\n            var values = new RouteValueDictionary();\n\n            return matcher.TryMatch(requestPath, values) ? values : null;\n        }\n\n        public bool IsMatch(string routeTemplate, string requestPath)\n        {\n            return Match(routeTemplate, requestPath) != null;\n        }\n\n        private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate)\n        {\n            var result = new RouteValueDictionary();\n\n            foreach (var parameter in parsedTemplate.Parameters)\n            {\n                if (parameter.DefaultValue != null)\n                {\n                    result.Add(parameter.Name, parameter.DefaultValue);\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Common/SimpleExceptionConverter.cs",
    "content": "﻿namespace Mockaco.Common\n{\n    using Newtonsoft.Json;\n    using Newtonsoft.Json.Linq;\n    using System;\n\n    internal class SimpleExceptionConverter : JsonConverter\n    {\n        public override bool CanConvert(Type objectType)\n        {\n            return typeof(Exception).IsAssignableFrom(objectType);\n        }\n\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            throw new NotImplementedException(\"Deserializing exceptions is not supported.\");\n        }\n\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            var exception = value as Exception;\n            if (exception == null)\n            {\n                serializer.Serialize(writer, null);\n                return;\n            }\n\n            var obj = new JObject\n            {\n                [\"Type\"] = exception.GetType().Name,\n                [\"Message\"] = exception.Message,\n\n            };\n\n            if (exception.Data.Count > 0)\n            {\n                obj[\"Data\"] = JToken.FromObject(exception.Data, serializer);\n            }\n\n            if (exception.InnerException != null)\n            {\n                obj[\"InnerException\"] = JToken.FromObject(exception.InnerException, serializer);\n            }\n\n            obj.WriteTo(writer);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Common/StringDictionary.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Mockaco\n{\n    public class StringDictionary : Dictionary<string, string>, IReadOnlyDictionary<string, string>\n    {\n        public new string this[string key]\n        {\n            get\n            {\n                if (TryGetValue(key, out string value))\n                {\n                    return value;\n                }\n\n                return string.Empty;\n            }\n            set\n            {\n                base[key] = value;\n            }\n        }\n\n        public new void Add(string key, string value)\n        {\n            Replace(key, value);\n        }\n\n        public void Replace(string key, string value)\n        {\n            if (ContainsKey(key))\n            {\n                Remove(key);\n            }\n\n            base.Add(key, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/DependencyInjection/MockacoApplicationBuilder.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Mockaco;\nusing Mockaco.Verifyer;\nusing Microsoft.Extensions.Diagnostics.HealthChecks;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Diagnostics.HealthChecks;\n\nnamespace Microsoft.AspNetCore.Builder\n{\n    public static class MockacoApplicationBuilder\n    {\n        public static IApplicationBuilder UseMockaco(this IApplicationBuilder app, Action<IApplicationBuilder> configure)\n        {\n            app.UseRouting();\n\n            var options = app.ApplicationServices.GetRequiredService<IOptions<MockacoOptions>>().Value;\n\n            var optionsChaos = app.ApplicationServices.GetRequiredService<IOptions<ChaosOptions>>().Value;\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.Map($\"/{options.VerificationEndpointPrefix ?? options.MockacoEndpoint}/{options.VerificationEndpointName}\", VerifyerExtensions.Verify);\n\n                endpoints.MapHealthChecks($\"/{options.MockacoEndpoint}/ready\", new HealthCheckOptions\n                {\n                    Predicate = healthCheck => healthCheck.Tags.Contains(\"ready\")\n                });\n\n                endpoints.MapHealthChecks($\"/{options.MockacoEndpoint}/health\", new HealthCheckOptions\n                {\n                    Predicate = _ => false\n                });\n            });\n\n            app.UseMiddleware<ErrorHandlingMiddleware>();\n            configure(app);\n            app\n                .UseMiddleware<RequestMatchingMiddleware>()\n                .UseMiddleware<ResponseDelayMiddleware>()\n                .UseMiddleware<ChaosMiddleware>()\n                .UseMiddleware<ResponseMockingMiddleware>()\n                .UseMiddleware<CallbackMiddleware>();\n\n            return app;\n        }\n\n        public static IApplicationBuilder UseMockaco(this IApplicationBuilder app) =>\n            app.UseMockaco(_ => { });\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/DependencyInjection/MockacoServiceCollection.cs",
    "content": "﻿using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Diagnostics.HealthChecks;\nusing Microsoft.Extensions.Options;\nusing Mockaco;\nusing Mockaco.Chaos.Strategies;\nusing Mockaco.HealthChecks;\nusing Mockaco.Settings;\n\nnamespace Microsoft.Extensions.DependencyInjection\n{\n    public static class MockacoServiceCollection\n    {\n        public static IServiceCollection AddMockaco(this IServiceCollection services) =>\n            services.AddMockaco(_ => { });\n\n        public static IServiceCollection AddMockaco(this IServiceCollection services, Action<MockacoOptions> config) =>\n            services\n                .AddOptions<MockacoOptions>().Configure(config).Services\n                .AddOptions<ChaosOptions>().Configure<IOptions<MockacoOptions>>((options, parent) => options = parent.Value.Chaos).Services\n                .AddOptions<TemplateFileProviderOptions>()\n                    .Configure<IOptions<MockacoOptions>>((options, parent) => options = parent.Value.TemplateFileProvider)\n                    .Services\n                .AddCommonServices();\n\n\n        public static IServiceCollection AddMockaco(this IServiceCollection services, IConfiguration config) =>\n            services\n                .AddConfiguration(config)\n                .AddCommonServices();\n\n        private static IServiceCollection AddConfiguration(this IServiceCollection services, IConfiguration config) =>\n            services\n                .AddOptions()\n                .Configure<MockacoOptions>(config)\n                .Configure<ChaosOptions>(config.GetSection(\"Chaos\"))\n                .Configure<TemplateFileProviderOptions>(config.GetSection(\"TemplateFileProvider\"));\n\n        private static IServiceCollection AddCommonServices(this IServiceCollection services)\n        {\n            services\n                .AddMemoryCache()\n                .AddHttpClient()\n                .AddInternalServices()\n                .AddChaosServices()\n                .AddHostedService<MockProviderWarmUp>();\n\n            services\n                .AddSingleton<StartupHealthCheck>()\n                .AddHealthChecks()\n                    .AddCheck<StartupHealthCheck>(\"Startup\", tags: new[] { \"ready\" });\n\n            return services;\n        }\n\n        private static IServiceCollection AddInternalServices(this IServiceCollection services) =>\n            services\n                .AddSingleton<VerificationRouteValueTransformer>()\n                .AddScoped<IMockacoContext, MockacoContext>()\n                .AddScoped<IScriptContext, ScriptContext>()\n                .AddTransient<IGlobalVariableStorage, ScriptContextGlobalVariableStorage>()\n\n                .AddSingleton<IScriptRunnerFactory, ScriptRunnerFactory>()\n\n                .AddSingleton<IFakerFactory, LocalizedFakerFactory>()\n                .AddSingleton<IMockProvider, MockProvider>()\n                .AddSingleton<ITemplateProvider, TemplateFileProvider>()\n\n                .AddScoped<IRequestMatcher, RequestMethodMatcher>()\n                .AddScoped<IRequestMatcher, RequestRouteMatcher>()\n                .AddScoped<IRequestMatcher, RequestConditionMatcher>()\n\n                .AddTransient<IRequestBodyFactory, RequestBodyFactory>()\n\n                .AddTransient<IRequestBodyStrategy, JsonRequestBodyStrategy>()\n                .AddTransient<IRequestBodyStrategy, XmlRequestBodyStrategy>()\n                .AddTransient<IRequestBodyStrategy, FormRequestBodyStrategy>()\n\n                .AddTransient<IResponseBodyFactory, ResponseBodyFactory>()\n\n                .AddTransient<IResponseBodyStrategy, BinaryResponseBodyStrategy>()\n                .AddTransient<IResponseBodyStrategy, JsonResponseBodyStrategy>()\n                .AddTransient<IResponseBodyStrategy, XmlResponseBodyStrategy>()\n                .AddTransient<IResponseBodyStrategy, DefaultResponseBodyStrategy>()\n\n                .AddTransient<ITemplateTransformer, TemplateTransformer>()\n\n                .AddTemplatesGenerating();\n\n        private static IServiceCollection AddChaosServices(this IServiceCollection services) =>\n            services\n                .AddTransient<IChaosStrategy, ChaosStrategyBehavior>()\n                .AddTransient<IChaosStrategy, ChaosStrategyException>()\n                .AddTransient<IChaosStrategy, ChaosStrategyLatency>()\n                .AddTransient<IChaosStrategy, ChaosStrategyResult>()\n                .AddTransient<IChaosStrategy, ChaosStrategyTimeout>();\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Extensions/EnumerableExtensions.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace System.Collections.Generic\n{\n    internal static class EnumerableExtensions\n    {\n        public static async Task<bool> AllAsync<TSource>(this IEnumerable<TSource> source, Func<TSource, Task<bool>> predicate)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null)\n                throw new ArgumentNullException(nameof(predicate));\n\n            foreach (var item in source)\n            {\n                var result = await predicate(item);\n                if (!result)\n                    return false;\n            }\n\n            return true;\n        }\n\n        public static async Task<bool> AllAsync<TSource>(this IEnumerable<Task<TSource>> source, Func<TSource, bool> predicate)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null)\n                throw new ArgumentNullException(nameof(predicate));\n\n            foreach (var item in source)\n            {\n                var awaitedItem = await item;\n                if (!predicate(awaitedItem))\n                    return false;\n            }\n\n            return true;\n        }\n        \n        public static T Random<T>(this IEnumerable<T> enumerable) { \n            int index = new Random().Next(0, enumerable.Count());\n            return enumerable.ElementAt(index);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Extensions/HttpRequestExtensions.cs",
    "content": "﻿/*\nThe MIT License (MIT)\n\nCopyright (c) 2015 Microsoft\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*/\n\nusing Microsoft.Net.Http.Headers;\nusing Mockaco;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Microsoft.AspNetCore.Http\n{\n    /// <summary>\n    /// Set of extension methods for Microsoft.AspNetCore.Http.HttpRequest\n    /// </summary>\n    internal static class HttpRequestExtensions\n    {\n        private const string UnknownHostName = \"UNKNOWN-HOST\";\n\n        /// <summary>\n        /// Gets http request Uri from request object\n        /// </summary>\n        /// <param name=\"request\">The <see cref=\"HttpRequest\"/></param>\n        /// <returns>A New Uri object representing request Uri</returns>\n        public static Uri GetUri(this HttpRequest request)\n        {\n            if (null == request)\n            {\n                throw new ArgumentNullException(nameof(request));\n            }\n\n            if (string.IsNullOrWhiteSpace(request.Scheme))\n            {\n                throw new ArgumentException(\"Http request Scheme is not specified\");\n            }\n\n            string hostName = request.Host.HasValue ? request.Host.ToString() : UnknownHostName;\n\n            var builder = new StringBuilder();\n\n            builder.Append(request.Scheme)\n                .Append(\"://\")\n                .Append(hostName);\n\n            if (request.Path.HasValue)\n            {\n                builder.Append(request.Path.Value);\n            }\n\n            if (request.QueryString.HasValue)\n            {\n                builder.Append(request.QueryString);\n            }\n\n            return new Uri(builder.ToString());\n        }\n\n        public static Routing.RouteValueDictionary GetRouteData(this HttpRequest request, Mock mock)\n        {\n            var routeMatcher = new RouteMatcher();\n\n            return routeMatcher.Match(mock.Route, request.Path);\n        }\n\n        public static bool HasXmlContentType(this HttpRequest request)\n        {\n            MediaTypeHeaderValue.TryParse(request.ContentType, out var parsedValue);\n\n            return parsedValue?.MediaType.Equals(HttpContentTypes.ApplicationXml, StringComparison.OrdinalIgnoreCase) == true\n                || parsedValue?.MediaType.Equals(HttpContentTypes.TextXml, StringComparison.OrdinalIgnoreCase) == true;\n        }\n\n        public static async Task<string> ReadBodyStream(this HttpRequest httpRequest)\n        {\n            httpRequest.EnableBuffering();\n\n            var encoding = GetEncodingFromContentType(httpRequest.ContentType) ?? Encoding.UTF8;\n            var reader = new StreamReader(httpRequest.Body, encoding); \n\n            var body = await reader.ReadToEndAsync();\n\n            if (httpRequest.Body.CanSeek)\n            {\n                httpRequest.Body.Seek(0, SeekOrigin.Begin);\n            }\n\n            return body;\n        }\n\n        public static IEnumerable<string> GetAcceptLanguageValues(this HttpRequest httpRequest)\n        {\n            var acceptLanguages = httpRequest.GetTypedHeaders().AcceptLanguage;\n\n            if(acceptLanguages == default)\n            {\n                return Enumerable.Empty<string>();\n            }\n\n            return acceptLanguages?.Select(l => l.Value.ToString());\n        }\n\n        private static Encoding GetEncodingFromContentType(string contentType)\n        {\n            // although the value is well parsed, the encoding is null when it is not informed\n            if (MediaTypeHeaderValue.TryParse(contentType, out var parsedValue))\n                return parsedValue.Encoding;\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Extensions/ObjectExtensions.cs",
    "content": "﻿using Mockaco.Common;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Converters;\nusing Newtonsoft.Json.Serialization;\nusing System.Linq;\n\nnamespace System\n{\n    internal static class ObjectExtensions\n    {\n        private static readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings\n        {\n            Formatting = Formatting.Indented,\n            Converters = new JsonConverter[] {\n                new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy()},\n                new SimpleExceptionConverter()\n            },\n            NullValueHandling = NullValueHandling.Ignore\n        };\n\n        public static string ToJson<T>(this T param)\n            where T : class\n        {\n            if (param == null)\n            {\n                return string.Empty;\n            }\n\n            try\n            {\n                return JsonConvert.SerializeObject(param, _jsonSerializerSettings);\n            }\n            catch\n            {\n                return string.Empty;\n            }\n        }\n\n        public static bool IsAnyOf<T>(this T item, params T[] possibleItems)\n        {\n            return possibleItems.Contains(item);\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Extensions/StringDictionaryExtensions.cs",
    "content": "﻿using Mockaco;\n\nnamespace System.Collections.Generic\n{\n    internal static class StringDictionaryExtensions\n    {\n        public static StringDictionary ToStringDictionary<TSource>(\n            this IEnumerable<TSource> source,\n            Func<TSource, string> keySelector,\n            Func<TSource, string> elementSelector)\n        {\n            var dictionary = new StringDictionary();\n\n            if (source == null)\n            {\n                return dictionary;\n            }\n\n            foreach (var item in source)\n            {\n                dictionary.Add(keySelector(item), elementSelector(item));\n            }\n\n            return dictionary;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Extensions/StringExtensions.cs",
    "content": "﻿using System.Text;\n\nnamespace System\n{\n    internal static class StringExtensions\n    {\n        public static string ToMD5Hash(this string input)\n        {\n            using (Security.Cryptography.MD5 md5 = Security.Cryptography.MD5.Create())\n            {\n                var inputBytes = Encoding.UTF8.GetBytes(input);\n                var hashBytes = md5.ComputeHash(inputBytes);\n\n                StringBuilder sb = new StringBuilder();\n                for (int i = 0; i < hashBytes.Length; i++)\n                {\n                    sb.Append(hashBytes[i].ToString(\"X2\"));\n                }\n                return sb.ToString();\n            }\n        }\n        \n        public static bool IsRemoteAbsolutePath(this string input)\n        {\n            if (Uri.TryCreate(input, UriKind.Absolute, out var uri))\n            {\n                return !uri.IsFile;\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/HealthChecks/StartupHealthCheck.cs",
    "content": "﻿using Microsoft.Extensions.Diagnostics.HealthChecks;\n\nnamespace Mockaco.HealthChecks\n{\n    public class StartupHealthCheck : IHealthCheck\n    {\n        private volatile bool _isReady;\n\n        public bool StartupCompleted\n        {\n            get => _isReady;\n            set => _isReady = value;\n        }\n\n        public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)\n        {\n            if (StartupCompleted)\n            {\n                return Task.FromResult(HealthCheckResult.Healthy(\"The startup has completed.\"));\n            }\n\n            return Task.FromResult(HealthCheckResult.Unhealthy(\"That startup is still running.\"));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/IMockProvider.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal interface IMockProvider\n    {\n        List<Mock> GetMocks();\n\n        IEnumerable<(string TemplateName, string ErrorMessage)> GetErrors();\n\n        Task WarmUp();\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/IMockacoContext.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Mockaco\n{\n    internal interface IMockacoContext\n    {\n        IScriptContext ScriptContext { get; }\n\n        Template TransformedTemplate { get; set; }\n\n        Mock Mock { get; set; }\n\n        List<Error> Errors { get; set; }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/InternalsVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Mockaco.AspNetCore.Tests\")]\n[assembly: InternalsVisibleTo(\"DynamicProxyGenAssembly2\")]\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Middlewares/CallbackMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Newtonsoft.Json;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class CallbackMiddleware\n    {\n        private readonly RequestDelegate _next;\n        private readonly ILogger<CallbackMiddleware> _logger;\n\n        public CallbackMiddleware(RequestDelegate next, ILogger<CallbackMiddleware> logger)\n        {\n            _next = next;\n            _logger = logger;\n        }\n\n        public Task Invoke(\n            HttpContext httpContext,\n            IMockacoContext mockacoContext,\n            IScriptContext scriptContext,\n            ITemplateTransformer templateTransformer,\n            IOptionsSnapshot<MockacoOptions> options)\n        {\n            if (mockacoContext.TransformedTemplate?.Callbacks?.Any() != true)\n            {\n                return Task.CompletedTask;\n            }\n\n            httpContext.Response.OnCompleted(\n                () =>\n                {\n                    //TODO Refactor to avoid method with too many parameters (maybe a CallbackRunnerFactory?)\n                    var fireAndForgetTask = PerformCallbacks(httpContext, mockacoContext, scriptContext, templateTransformer, options.Value);\n                    return Task.CompletedTask;\n                });\n\n            return Task.CompletedTask;\n        }\n        \n        private async Task PerformCallbacks(\n            HttpContext httpContext,\n            IMockacoContext mockacoContext,\n            IScriptContext scriptContext,\n            ITemplateTransformer templateTransformer,\n            MockacoOptions options)\n        {\n            try\n            {\n                var stopwatch = Stopwatch.StartNew();\n                                \n                var template = await templateTransformer.Transform(mockacoContext.Mock.RawTemplate, scriptContext);\n\n                var callbackTasks = new List<Task>();\n\n                foreach (var callbackTemplate in template.Callbacks)\n                {\n                    callbackTasks.Add(PerformCallback(httpContext, callbackTemplate, options, stopwatch.ElapsedMilliseconds));\n                }\n\n                await Task.WhenAll(callbackTasks);\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex, \"Error preparing callback(s)\");\n            }\n        }\n\n        private async Task PerformCallback(HttpContext httpContext, CallbackTemplate callbackTemplate, MockacoOptions options, long elapsedMilliseconds)\n        {\n            try\n            {\n                var request = PrepareHttpRequest(callbackTemplate, options);\n\n                var httpClient = PrepareHttpClient(httpContext, callbackTemplate);\n\n                await DelayRequest(callbackTemplate, elapsedMilliseconds);\n\n                var stopwatch = Stopwatch.StartNew();\n\n                _logger.LogDebug(\"Callback started\");\n\n                await PerformRequest(request, httpClient);\n\n                _logger.LogDebug(\"Callback finished in {0} ms\", stopwatch.ElapsedMilliseconds);\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex, \"Callback error\");\n            }\n        }\n\n        private static HttpRequestMessage PrepareHttpRequest(CallbackTemplate callbackTemplate, MockacoOptions options)\n        {\n            var request = new HttpRequestMessage(new HttpMethod(callbackTemplate.Method), callbackTemplate.Url);\n\n            var formatting = callbackTemplate.Indented.GetValueOrDefault(true) ? Formatting.Indented : default;\n\n            if (callbackTemplate.Body != null)\n            {\n                request.Content = callbackTemplate.Headers?.ContainsKey(HttpHeaders.ContentType) == true\n                    ? new StringContent(callbackTemplate.Body.ToString(), Encoding.UTF8, callbackTemplate.Headers[HttpHeaders.ContentType])\n                    : new StringContent(callbackTemplate.Body.ToString(formatting));\n            }\n\n            PrepareHeaders(callbackTemplate, request, options);\n\n            return request;\n        }\n\n        private static void PrepareHeaders(CallbackTemplate callBackTemplate, HttpRequestMessage httpRequest, MockacoOptions options)\n        {\n            if (callBackTemplate.Headers != null)\n            {\n                foreach (var header in callBackTemplate.Headers.Where(h => h.Key != HttpHeaders.ContentType))\n                {\n                    if (httpRequest.Headers.Contains(header.Key))\n                    {\n                        httpRequest.Headers.Remove(header.Key);\n                    }\n\n                    httpRequest.Headers.Add(header.Key, header.Value);\n                }\n            }\n\n            if (!httpRequest.Headers.Accept.Any())\n            {\n                httpRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(options.DefaultHttpContentType));\n            }\n        }\n\n        private static HttpClient PrepareHttpClient(HttpContext httpContext, CallbackTemplate callbackTemplate)\n        {\n            var factory = httpContext.RequestServices.GetService<IHttpClientFactory>();\n            var httpClient = factory.CreateClient();\n\n            httpClient.Timeout = TimeSpan.FromMilliseconds(callbackTemplate.Timeout.GetValueOrDefault());\n\n            return httpClient;\n        }\n\n        private async Task DelayRequest(CallbackTemplate callbackTemplate, long elapsedMilliseconds)\n        {\n            var remainingDelay = TimeSpan.FromMilliseconds(callbackTemplate.Delay.GetValueOrDefault() - elapsedMilliseconds);\n            if (elapsedMilliseconds < remainingDelay.TotalMilliseconds)\n            {\n                _logger.LogDebug(\"Callback delay: {0} milliseconds\", remainingDelay.TotalMilliseconds);\n                await Task.Delay(remainingDelay);\n            }\n        }\n\n        private async Task PerformRequest(HttpRequestMessage request, HttpClient httpClient)\n        {\n            try\n            {\n                var response = await httpClient.SendAsync(request);\n\n                _logger.LogDebug(\"Callback response\\n\\n{0}\\n\", response);\n                _logger.LogDebug(\"Callback response content\\n\\n{0}\\n\", await response.Content.ReadAsStringAsync());\n            }\n            catch (OperationCanceledException)\n            {\n                _logger.LogError(\"Callback request timeout\");\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex, \"Callback error\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Middlewares/ChaosMiddleware.cs",
    "content": "using System.Net;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Mockaco.Chaos.Strategies;\n\nnamespace Mockaco;\n\ninternal class ChaosMiddleware\n{\n    private readonly RequestDelegate _next;\n    private readonly IEnumerable<IChaosStrategy> _strategies;\n    private readonly ILogger<ChaosMiddleware> _logger;\n    private readonly IOptions<ChaosOptions> _options;\n\n    private List<int> ErrorList { get; set; }\n    private int Counter { get; set; }\n\n    public ChaosMiddleware(\n        RequestDelegate next,\n        IEnumerable<IChaosStrategy> strategies,\n        ILogger<ChaosMiddleware> logger,\n        IOptions<ChaosOptions> options)\n    {\n        _next = next;\n        _strategies = strategies;\n        _logger = logger;\n        _options = options;\n    }\n\n    public async Task Invoke(HttpContext httpContext)\n    {\n        if (!_options.Value.Enabled)\n        {\n            await _next(httpContext);\n            return;\n        }\n\n        Counter++;\n        if (Counter > 100)\n            Counter = 1;\n\n        if (Counter == 1)\n            ErrorList = GenerateErrorList(_options.Value.ChaosRate);\n\n        if (ErrorList.Contains(Counter))\n        {\n            var selected = _strategies.Random();\n            _logger.LogInformation($\"Chaos: {selected?.ToString()}\");\n            if (selected != null) await selected.Response(httpContext.Response);\n        }\n\n        if (httpContext.Response.StatusCode != (int)HttpStatusCode.OK)\n            return;\n\n        await _next(httpContext);\n    }\n\n    private List<int> GenerateErrorList(int rate)\n    {\n        var list = new List<int>();\n        while (list.Count < rate)\n        {\n            var item = new Random().Next(1, 100);\n            if (!list.Contains(item))\n            {\n                list.Add(item);\n            }\n        }\n\n        return list.OrderBy(x => x).ToList();\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Middlewares/ErrorHandlingMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing System;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class ErrorHandlingMiddleware\n    {\n        private readonly RequestDelegate _next;\n\n        public ErrorHandlingMiddleware(RequestDelegate next)\n        {\n            _next = next;\n        }\n\n        public async Task Invoke(\n            HttpContext httpContext,\n            IMockacoContext mockacoContext,\n            IOptionsSnapshot<MockacoOptions> statusCodeOptions,\n            IMockProvider mockProvider,\n            ILogger<ErrorHandlingMiddleware> logger)\n        {\n            try\n            {\n                await _next(httpContext);\n            }\n            catch (Exception ex)\n            {\n                logger.LogError(ex, \"Error generating mocked response\");\n\n                mockacoContext.Errors.Add(new Error(\"Error generating mocked response\", ex));\n            }\n            finally\n            {\n                if (mockacoContext.Errors.Any() && !httpContext.Response.HasStarted)\n                {\n                    httpContext.Response.StatusCode = (int)statusCodeOptions.Value.ErrorHttpStatusCode;\n                    httpContext.Response.ContentType = HttpContentTypes.ApplicationJson;\n\n                    IncludeMockProviderErrors(mockacoContext, mockProvider);\n\n                    await httpContext.Response.WriteAsync(mockacoContext.Errors.ToJson());\n                }\n            }\n        }\n\n        private static void IncludeMockProviderErrors(IMockacoContext mockacoContext, IMockProvider mockProvider)\n        {\n            mockacoContext.Errors\n                .AddRange(mockProvider.GetErrors()\n                    .Select(_ => new Error($\"{_.TemplateName} - {_.ErrorMessage}\")));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Middlewares/RequestMatchingMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Caching.Memory;\nusing Microsoft.Extensions.Options;\n\nnamespace Mockaco\n{\n    internal class RequestMatchingMiddleware\n    {\n        private readonly RequestDelegate _next;\n        private readonly ILogger<RequestMatchingMiddleware> _logger;\n\n        public RequestMatchingMiddleware(RequestDelegate next, ILogger<RequestMatchingMiddleware> logger)\n        {\n            _next = next;\n            _logger = logger;\n        }\n\n        public async Task Invoke(\n            HttpContext httpContext,\n            IMockacoContext mockacoContext,\n            IScriptContext scriptContext,\n            IMockProvider mockProvider,\n            ITemplateTransformer templateTransformer,\n            IEnumerable<IRequestMatcher> requestMatchers,\n            IMemoryCache cache,\n            IOptions<MockacoOptions> options\n            )\n        {\n            await LogHttpContext(httpContext);\n\n            await AttachRequestToScriptContext(httpContext, mockacoContext, scriptContext);\n\n            if (mockacoContext.Errors.Any())\n            {\n                return;\n            }\n\n            foreach (var mock in mockProvider.GetMocks())\n            {\n                if (await requestMatchers.AllAsync(_ => _.IsMatch(httpContext.Request, mock)))\n                {\n                    cache.Set($\"{nameof(RequestMatchingMiddleware)} {httpContext.Request.Path.Value}\",new\n                    {\n                        Route = httpContext.Request.Path.Value,\n                        Timestamp = $\"{DateTime.Now.ToString(\"t\")}\",\n                        Headers = LoadHeaders(httpContext, options.Value.VerificationIgnoredHeaders),\n                        Body = await httpContext.Request.ReadBodyStream()\n                    }, DateTime.Now.AddMinutes(options.Value.MatchedRoutesCacheDuration));\n\n                    _logger.LogInformation(\"Incoming request matched {mock}\", mock);\n\n                    await scriptContext.AttachRouteParameters(httpContext.Request, mock);\n\n                    var template = await templateTransformer.TransformAndSetVariables(mock.RawTemplate, scriptContext);\n\n                    mockacoContext.Mock = mock;\n                    mockacoContext.TransformedTemplate = template;\n\n                    await _next(httpContext);\n\n                    return;\n                }\n                else\n                {\n                    _logger.LogDebug(\"Incoming request didn't match {mock}\", mock);\n                }\n            }\n\n            _logger.LogInformation(\"Incoming request didn't match any mock\");\n\n            mockacoContext.Errors.Add(new Error(\"Incoming request didn't match any mock\"));\n        }\n\n        //TODO Remove redundant code\n        private async Task AttachRequestToScriptContext(HttpContext httpContext, IMockacoContext mockacoContext, IScriptContext scriptContext)\n        {\n            try\n            {\n                await scriptContext.AttachRequest(httpContext.Request);\n            }\n            catch (Exception ex)\n            {\n                mockacoContext.Errors.Add(new Error(\"An error occurred while reading request\", ex));\n\n                _logger.LogWarning(ex, \"An error occurred while reading request\");\n\n                return;\n            }\n        }\n\n        private async Task LogHttpContext(HttpContext httpContext)\n        {\n            _logger.LogInformation(\"Incoming request from {remoteIp}\", httpContext.Connection.RemoteIpAddress);\n\n            _logger.LogDebug(\"Headers: {headers}\", httpContext.Request.Headers.ToJson());\n\n            var body = await httpContext.Request.ReadBodyStream();\n\n            if (string.IsNullOrEmpty(body))\n            {\n                _logger.LogDebug(\"Body is not present\");\n            }\n            else\n            {\n                _logger.LogDebug(\"Body: {body}\", body);\n            }\n        }\n\n        private static IEnumerable<object> LoadHeaders(HttpContext httpContext, IEnumerable<string> verificationIgnoredHeaders)\n        {            \n            return from header in httpContext.Request.Headers.ToList()\n                   where !verificationIgnoredHeaders.Any(opt => opt == header.Key)\n                   select new { header.Key, Value = header.Value[0] };\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Middlewares/ResponseDelayMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class ResponseDelayMiddleware\n    {\n        private readonly RequestDelegate _next;\n\n        public ResponseDelayMiddleware(RequestDelegate next)\n        {\n            _next = next;\n        }\n\n        public async Task Invoke(HttpContext httpContext, IMockacoContext mockacoContext, ILogger<ResponseDelayMiddleware> logger)\n        {\n            var transformedTemplate = mockacoContext.TransformedTemplate;\n            if (transformedTemplate == default)\n            {\n                return;\n            }\n\n            int responseDelay = transformedTemplate.Response?.Delay.GetValueOrDefault() ?? 0;\n            if (responseDelay > 0)\n            {\n                logger.LogDebug(\"Response delay: {responseDelay} milliseconds\", responseDelay);\n\n                await Task.Delay(responseDelay);\n            }\n\n            await _next(httpContext);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Middlewares/ResponseMockingMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Options;\nusing System.Net;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class ResponseMockingMiddleware\n    {\n        private readonly RequestDelegate _next;\n\n        public ResponseMockingMiddleware(RequestDelegate next)\n        {\n            _next = next;\n        }\n\n        public async Task Invoke(\n            HttpContext httpContext,\n            IMockacoContext mockacoContext,\n            IScriptContext scriptContext,\n            IResponseBodyFactory responseBodyFactory,\n            IOptionsSnapshot<MockacoOptions> options)\n        {\n            await PrepareResponse(httpContext.Response, mockacoContext.TransformedTemplate, responseBodyFactory, options.Value);\n\n            await scriptContext.AttachResponse(httpContext.Response, mockacoContext.TransformedTemplate.Response);\n\n            await _next(httpContext);\n        }\n\n        private async Task PrepareResponse(\n            HttpResponse httpResponse,\n            Template transformedTemplate,\n            IResponseBodyFactory responseBodyFactory,\n            MockacoOptions options)\n        {\n            httpResponse.StatusCode = GetResponseStatusFromTemplate(transformedTemplate.Response, options);\n\n            AddHeadersFromTemplate(httpResponse, transformedTemplate.Response, options);\n\n            var bodyBytes = await responseBodyFactory.GetResponseBodyBytesFromTemplate(transformedTemplate.Response);\n\n            if (bodyBytes == default)\n            {\n                return;\n            }\n\n            await httpResponse.Body.WriteAsync(bodyBytes, 0, bodyBytes.Length, default);\n        }\n\n        private int GetResponseStatusFromTemplate(ResponseTemplate responseTemplate, MockacoOptions options)\n        {\n            return responseTemplate?.Status == default(HttpStatusCode)\n                            ? (int)options.DefaultHttpStatusCode\n                            : (int)responseTemplate.Status;\n        }\n\n        private void AddHeadersFromTemplate(HttpResponse response, ResponseTemplate responseTemplate, MockacoOptions options)\n        {\n            if (responseTemplate?.Headers != null)\n            {\n                foreach (var header in responseTemplate.Headers)\n                {\n                    response.Headers.Add(header.Key, header.Value);\n                }\n            }\n\n            if (string.IsNullOrEmpty(response.ContentType))\n            {\n                response.ContentType = options.DefaultHttpContentType;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/MockProvider.cs",
    "content": "﻿using Microsoft.Extensions.Diagnostics.HealthChecks;\nusing Microsoft.Extensions.Logging;\nusing Mockaco.HealthChecks;\nusing Mono.TextTemplating;\nusing Newtonsoft.Json;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class MockProvider : IMockProvider\n    {\n        private List<Mock> _cache;\n        private readonly List<(string TemplateName, string ErrorMessage)> _errors = new List<(string TemplateName, string Error)>();        \n        private readonly IFakerFactory _fakerFactory;\n        private readonly IRequestBodyFactory _requestBodyFactory;\n        private readonly ITemplateProvider _templateProvider;\n        private readonly ITemplateTransformer _templateTransformer;\n        private readonly IGlobalVariableStorage _globalVariableStorage;\n        private readonly StartupHealthCheck _healthCheck;\n        private readonly ILogger<MockProvider> _logger;\n\n        public MockProvider\n            (IFakerFactory fakerFactory, \n            IRequestBodyFactory requestBodyFactory, \n            ITemplateProvider templateProvider, \n            ITemplateTransformer templateTransformer, \n            IGlobalVariableStorage globalVariableStorage,\n            StartupHealthCheck healthCheck,\n            ILogger<MockProvider> logger)\n        {\n            _cache = new List<Mock>();\n            _fakerFactory = fakerFactory;\n            _requestBodyFactory = requestBodyFactory;\n            _templateProvider = templateProvider;\n            _templateProvider.OnChange += TemplateProviderChange;\n\n            _templateTransformer = templateTransformer;\n            _globalVariableStorage = globalVariableStorage;\n            _healthCheck = healthCheck;\n            _logger = logger;\n        }\n\n        private async void TemplateProviderChange(object sender, EventArgs e)\n        {\n            await WarmUp();\n        }\n\n        //TODO: Fix potential thread-unsafe method\n        public List<Mock> GetMocks()\n        {\n            return _cache;\n        }\n\n        public IEnumerable<(string TemplateName, string ErrorMessage)> GetErrors()\n        {\n            return _errors;\n        }\n\n        public async Task WarmUp()\n        {\n            var stopwatch = Stopwatch.StartNew();\n\n            var warmUpScriptContext = new ScriptContext(_fakerFactory, _requestBodyFactory, _globalVariableStorage);\n\n            const int defaultCapacity = 16;\n            var mocks = new List<Mock>(_cache.Count > 0 ? _cache.Count : defaultCapacity);\n\n            _errors.Clear();\n\n            foreach (var rawTemplate in _templateProvider.GetTemplates())\n            {\n                try\n                {\n                    var existentCachedRoute = _cache.FirstOrDefault(cachedRoute => cachedRoute.RawTemplate.Hash == rawTemplate.Hash);\n\n                    if (existentCachedRoute != default)\n                    {\n                        _logger.LogDebug(\"Using cached {0} ({1})\", rawTemplate.Name, rawTemplate.Hash);\n\n                        mocks.Add(existentCachedRoute);\n\n                        continue;\n                    }\n\n                    _logger.LogDebug(\"Loading {0} ({1})\", rawTemplate.Name, rawTemplate.Hash);\n\n                    var template = await _templateTransformer.Transform(rawTemplate, warmUpScriptContext);\n                    var mock = CreateMock(rawTemplate, template.Request);\n\n                    mocks.Add(mock);\n\n                    _logger.LogInformation(\"{method} {route} mapped from {templateName}\", template.Request?.Method, template.Request?.Route, rawTemplate.Name);\n                }\n                catch (JsonReaderException ex)\n                {\n                    _errors.Add((rawTemplate.Name, $\"Generated JSON is invalid - {ex.Message}\"));\n                    \n                    _logger.LogWarning(\"Skipping {0}: Generated JSON is invalid - {1}\", rawTemplate.Name, ex.Message);\n                }\n                catch (ParserException ex)\n                {\n                    _errors.Add((rawTemplate.Name, $\"Script parser error - {ex.Message} {ex.Location}\"));\n\n                    _logger.LogWarning(\"Skipping {0}: Script parser error - {1} {2} \", rawTemplate.Name, ex.Message, ex.Location);\n                }\n                catch (Exception ex)\n                {\n                    _errors.Add((rawTemplate.Name, ex.Message));\n\n                    _logger.LogWarning(\"Skipping {0}: {1}\", rawTemplate.Name, ex.Message);\n                }\n            }\n\n            _cache.Clear();\n\n            _cache = mocks.OrderByDescending(r => r.HasCondition).ToList();\n\n            _healthCheck.StartupCompleted = true;\n\n            _logger.LogTrace(\"{0} finished in {1} ms\", nameof(WarmUp), stopwatch.ElapsedMilliseconds);\n        }\n\n        private static Mock CreateMock(IRawTemplate rawTemplate, RequestTemplate requestTemplate)\n        {\n            return new Mock(requestTemplate?.Method, requestTemplate?.Route, rawTemplate, requestTemplate?.Condition != default);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Mockaco.AspNetCore.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net6.0</TargetFramework>\n\t\t<LangVersion>latest</LangVersion>\n\t\t<AssemblyName>Mockaco.AspNetCore</AssemblyName>\n\t\t<RootNamespace>Mockaco</RootNamespace>\n\t\t<ImplicitUsings>enable</ImplicitUsings>\n\t\t<Configurations>Debug;Release;Nuget</Configurations>\n\t\t<TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n\t</PropertyGroup>\n\n\t<PropertyGroup>\n\t\t<IsPackable>true</IsPackable>\n\t\t<PackageOutputPath>./nupkg</PackageOutputPath>\n\t\t<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>\n\t\t<Authors>natenho</Authors>\n\t\t<Description>ASP.NET Core pipeline to mock HTTP requests/responses, useful to stub services and simulate dynamic API responses, leveraging ASP.NET Core features, built-in fake data generation and pure C# scripting</Description>\n\t\t<PackageProjectUrl>https://github.com/natenho/Mockaco</PackageProjectUrl>\n\t\t<RepositoryUrl>https://github.com/natenho/Mockaco</RepositoryUrl>\n\t\t<PackageTags>mock http aspnetcore</PackageTags>\n\t\t<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>\n\t\t<PackageIcon>mockaco-icon.png</PackageIcon>\n\t\t<Product>Mockaco</Product>\n\t</PropertyGroup>\n\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n\t\t<NoWarn>1701;1702;NU5104</NoWarn>\n\t\t<WarningsNotAsErrors>AD0001;NU5104</WarningsNotAsErrors>\n\t</PropertyGroup>\n\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|AnyCPU'\">\n\t\t<NoWarn>1701;1702;NU5104</NoWarn>\n\t\t<WarningsNotAsErrors>AD0001;NU5104</WarningsNotAsErrors>\n\t</PropertyGroup>\n\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Nuget|AnyCPU'\">\n\t\t<NoWarn>1701;1702;NU5104</NoWarn>\n\t\t<WarningsNotAsErrors>AD0001;NU5104</WarningsNotAsErrors>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n\t\t<FrameworkReference Include=\"Microsoft.AspNetCore.App\" />\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<PackageReference Include=\"Bogus\" Version=\"34.0.2\" />\n\t\t<PackageReference Include=\"GitVersion.MsBuild\" Version=\"5.12.0\">\n\t\t\t<PrivateAssets>all</PrivateAssets>\n\t\t\t<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n\t\t</PackageReference>\n\t\t<PackageReference Include=\"MAB.DotIgnore\" Version=\"3.0.2\" />\n\t\t<PackageReference Include=\"Microsoft.OpenApi.Readers\" Version=\"1.6.4\" />\n\t\t<PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Scripting\" Version=\"4.6.0\" />\n\t\t<PackageReference Include=\"Microsoft.CodeAnalysis.PublicApiAnalyzers\" Version=\"3.3.4\">\n\t\t\t<PrivateAssets>all</PrivateAssets>\n\t\t\t<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n\t\t</PackageReference>\n\t\t<PackageReference Include=\"Newtonsoft.Json\" Version=\"13.0.3\" />\n\t\t<PackageReference Include=\"Polly\" Version=\"7.2.3\" />\n\t\t<PackageReference Include=\"System.CommandLine\" Version=\"2.0.0-beta1.21308.1\" />\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<AssemblyAttribute Include=\"System.Runtime.CompilerServices.InternalsVisibleTo\">\n\t\t\t<_Parameter1>Mockaco.Tests</_Parameter1>\n\t\t</AssemblyAttribute>\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<None Include=\"Resources\\mockaco-icon.png\">\n\t\t\t<Pack>True</Pack>\n\t\t\t<PackagePath>/</PackagePath>\n\t\t</None>\n\t</ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/MockacoContext.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Mockaco\n{\n    internal class MockacoContext : IMockacoContext\n    {\n        public IScriptContext ScriptContext { get; set; }\n\n        public Template TransformedTemplate { get; set; }\n\n        public Mock Mock { get; set; }\n\n        public List<Error> Errors { get; set; }\n                \n        public MockacoContext(IScriptContext scriptContext)\n        {\n            ScriptContext = scriptContext;\n            Errors = new List<Error>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Options/ChaosOptions.cs",
    "content": "namespace Mockaco;\n\npublic class ChaosOptions\n{\n    public bool Enabled { get; set; }\n    public int ChaosRate { get; set; }\n    public int MinimumLatencyTime { get; set; }\n    public int MaximumLatencyTime { get; set; }\n    public int TimeBeforeTimeout { get; set; }\n\n    public ChaosOptions()\n    {\n        Enabled = false;\n        ChaosRate = 10;\n        MinimumLatencyTime = 500;\n        MaximumLatencyTime = 3000;\n        TimeBeforeTimeout = 10000;\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Options/MockacoOptions.cs",
    "content": "﻿using System.Net;\n\nnamespace Mockaco\n{\n    public class MockacoOptions\n    {\n        public HttpStatusCode DefaultHttpStatusCode { get; set; }\n\n        public HttpStatusCode ErrorHttpStatusCode { get; set; }       \n\n        public string DefaultHttpContentType { get; set; }\n\n        public List<string> References { get; set; }\n\n        public List<string> VerificationIgnoredHeaders { get; set; }\n        \n        public List<string> Imports { get; set; }\n\n        public int MatchedRoutesCacheDuration { get; set; }\n\n        public string MockacoEndpoint { get; set; }\n\n        // Deprecated (use MockacoEndpoint instead)\n        public string VerificationEndpointPrefix { get; set; }\n        \n        public ChaosOptions Chaos { get; set; }\n\n        public string VerificationEndpointName { get; set; }\n\n        public TemplateFileProviderOptions TemplateFileProvider { get; set; }\n\n        public MockacoOptions()\n        {\n            DefaultHttpStatusCode = HttpStatusCode.OK;\n            ErrorHttpStatusCode = HttpStatusCode.NotImplemented;\n            DefaultHttpContentType = HttpContentTypes.ApplicationJson;\n            References = new List<string>();\n            Imports = new List<string>();\n            MatchedRoutesCacheDuration = 60;\n            MockacoEndpoint = \"_mockaco\";\n            VerificationEndpointName = \"verification\";\n            TemplateFileProvider = new();\n            Chaos = new ChaosOptions();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Options/TemplateFileProviderOptions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    public class TemplateFileProviderOptions\n    {\n        public string Path { get; set; }\n\n        public TemplateFileProviderOptions()\n        {\n            Path = \"Mocks\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Plugins/PhoneNumberExtensions.cs",
    "content": "﻿using Bogus.DataSets;\n\nnamespace Bogus\n{\n    // TODO Move to plugin\n    public static class PhoneNumberExtensions\n    {\n        public static string BrazilianPhoneNumber(this PhoneNumbers phoneNumbers)\n        {\n            var faker = new Faker(\"pt_BR\");\n            string[] brazilianAreaCodes = { \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"21\", \"22\", \"24\", \"27\", \"28\", \"31\", \"32\", \"33\", \"34\", \"35\", \"37\", \"38\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\", \"51\", \"53\", \"54\", \"55\", \"61\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"69\", \"71\", \"73\", \"74\", \"75\", \"77\", \"79\", \"81\", \"82\", \"83\", \"84\", \"85\", \"86\", \"87\", \"88\", \"89\", \"91\", \"92\", \"93\", \"94\", \"95\", \"96\", \"97\", \"98\", \"99\" };\n            var areaCode = faker.PickRandom(brazilianAreaCodes);\n            var sufix = faker.Random.Number(50000000, 99999999);\n            return $\"{areaCode}9{sufix}\";\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/PublicAPI.Shipped.txt",
    "content": "﻿"
  },
  {
    "path": "src/Mockaco.AspNetCore/PublicAPI.Unshipped.txt",
    "content": "﻿Bogus.PhoneNumberExtensions\nMicrosoft.AspNetCore.Builder.MockacoApplicationBuilder\nMicrosoft.Extensions.DependencyInjection.MockacoServiceCollection\nMockaco.ChaosOptions\nMockaco.ChaosOptions.ChaosOptions() -> void\nMockaco.ChaosOptions.ChaosRate.get -> int\nMockaco.ChaosOptions.ChaosRate.set -> void\nMockaco.ChaosOptions.Enabled.get -> bool\nMockaco.ChaosOptions.Enabled.set -> void\nMockaco.ChaosOptions.MaximumLatencyTime.get -> int\nMockaco.ChaosOptions.MaximumLatencyTime.set -> void\nMockaco.ChaosOptions.MinimumLatencyTime.get -> int\nMockaco.ChaosOptions.MinimumLatencyTime.set -> void\nMockaco.ChaosOptions.TimeBeforeTimeout.get -> int\nMockaco.ChaosOptions.TimeBeforeTimeout.set -> void\nMockaco.HealthChecks.StartupHealthCheck\nMockaco.HealthChecks.StartupHealthCheck.CheckHealthAsync(Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult>\nMockaco.HealthChecks.StartupHealthCheck.StartupCompleted.get -> bool\nMockaco.HealthChecks.StartupHealthCheck.StartupCompleted.set -> void\nMockaco.HealthChecks.StartupHealthCheck.StartupHealthCheck() -> void\nMockaco.IFakerFactory\nMockaco.IFakerFactory.GetDefaultFaker() -> Bogus.Faker\nMockaco.IFakerFactory.GetFaker(System.Collections.Generic.IEnumerable<string> acceptLanguages) -> Bogus.Faker\nMockaco.IGlobalVariableStorage\nMockaco.IGlobalVariableStorage.Clear() -> void\nMockaco.IGlobalVariableStorage.DisableWriting() -> void\nMockaco.IGlobalVariableStorage.EnableWriting() -> void\nMockaco.IGlobalVariableStorage.this[string name].get -> object\nMockaco.IGlobalVariableStorage.this[string name].set -> void\nMockaco.IRawTemplate\nMockaco.IRawTemplate.Content.get -> string\nMockaco.IRawTemplate.Hash.get -> string\nMockaco.IRawTemplate.Name.get -> string\nMockaco.IRequestBodyFactory\nMockaco.IRequestBodyFactory.ReadBodyAsJson(Microsoft.AspNetCore.Http.HttpRequest httpRequest) -> System.Threading.Tasks.Task<Newtonsoft.Json.Linq.JToken>\nMockaco.IScriptContext\nMockaco.IScriptContext.AttachRequest(Microsoft.AspNetCore.Http.HttpRequest httpRequest) -> System.Threading.Tasks.Task\nMockaco.IScriptContext.AttachResponse(Microsoft.AspNetCore.Http.HttpResponse httpResponse, Mockaco.ResponseTemplate responseTemplate) -> System.Threading.Tasks.Task\nMockaco.IScriptContext.AttachRouteParameters(Microsoft.AspNetCore.Http.HttpRequest httpRequest, Mockaco.Mock route) -> System.Threading.Tasks.Task\nMockaco.IScriptContext.Faker.get -> Bogus.Faker\nMockaco.IScriptContext.Global.get -> Mockaco.IGlobalVariableStorage\nMockaco.IScriptContext.Request.get -> Mockaco.ScriptContextRequest\nMockaco.IScriptContext.Request.set -> void\nMockaco.IScriptContext.Response.get -> Mockaco.ScriptContextResponse\nMockaco.IScriptContext.Response.set -> void\nMockaco.Mock\nMockaco.Mock.HasCondition.get -> bool\nMockaco.Mock.HasCondition.set -> void\nMockaco.Mock.Method.get -> string\nMockaco.Mock.Method.set -> void\nMockaco.Mock.Mock(string method, string route, Mockaco.IRawTemplate rawTemplate, bool hasCondition) -> void\nMockaco.Mock.RawTemplate.get -> Mockaco.IRawTemplate\nMockaco.Mock.RawTemplate.set -> void\nMockaco.Mock.Route.get -> string\nMockaco.Mock.Route.set -> void\nMockaco.MockacoOptions\nMockaco.MockacoOptions.Chaos.get -> Mockaco.ChaosOptions\nMockaco.MockacoOptions.Chaos.set -> void\nMockaco.MockacoOptions.DefaultHttpContentType.get -> string\nMockaco.MockacoOptions.DefaultHttpContentType.set -> void\nMockaco.MockacoOptions.DefaultHttpStatusCode.get -> System.Net.HttpStatusCode\nMockaco.MockacoOptions.DefaultHttpStatusCode.set -> void\nMockaco.MockacoOptions.ErrorHttpStatusCode.get -> System.Net.HttpStatusCode\nMockaco.MockacoOptions.ErrorHttpStatusCode.set -> void\nMockaco.MockacoOptions.VerificationIgnoredHeaders.get -> System.Collections.Generic.List<string>\nMockaco.MockacoOptions.VerificationIgnoredHeaders.set -> void\nMockaco.MockacoOptions.Imports.get -> System.Collections.Generic.List<string>\nMockaco.MockacoOptions.Imports.set -> void\nMockaco.MockacoOptions.MatchedRoutesCacheDuration.get -> int\nMockaco.MockacoOptions.MatchedRoutesCacheDuration.set -> void\nMockaco.MockacoOptions.MockacoEndpoint.get -> string\nMockaco.MockacoOptions.MockacoEndpoint.set -> void\nMockaco.MockacoOptions.MockacoOptions() -> void\nMockaco.MockacoOptions.References.get -> System.Collections.Generic.List<string>\nMockaco.MockacoOptions.References.set -> void\nMockaco.MockacoOptions.TemplateFileProvider.get -> Mockaco.TemplateFileProviderOptions\nMockaco.MockacoOptions.TemplateFileProvider.set -> void\nMockaco.MockacoOptions.VerificationEndpointName.get -> string\nMockaco.MockacoOptions.VerificationEndpointName.set -> void\nMockaco.MockacoOptions.VerificationEndpointPrefix.get -> string\nMockaco.MockacoOptions.VerificationEndpointPrefix.set -> void\nMockaco.ResponseTemplate\nMockaco.ResponseTemplate.Body.get -> Newtonsoft.Json.Linq.JToken\nMockaco.ResponseTemplate.Body.set -> void\nMockaco.ResponseTemplate.Delay.get -> int?\nMockaco.ResponseTemplate.Delay.set -> void\nMockaco.ResponseTemplate.File.get -> string\nMockaco.ResponseTemplate.File.set -> void\nMockaco.ResponseTemplate.Headers.get -> System.Collections.Generic.IDictionary<string, string>\nMockaco.ResponseTemplate.Headers.set -> void\nMockaco.ResponseTemplate.Indented.get -> bool?\nMockaco.ResponseTemplate.Indented.set -> void\nMockaco.ResponseTemplate.ResponseTemplate() -> void\nMockaco.ResponseTemplate.Status.get -> System.Net.HttpStatusCode\nMockaco.ResponseTemplate.Status.set -> void\nMockaco.ScriptContext\nMockaco.ScriptContext.AttachRequest(Microsoft.AspNetCore.Http.HttpRequest httpRequest) -> System.Threading.Tasks.Task\nMockaco.ScriptContext.AttachResponse(Microsoft.AspNetCore.Http.HttpResponse httpResponse, Mockaco.ResponseTemplate responseTemplate) -> System.Threading.Tasks.Task\nMockaco.ScriptContext.AttachRouteParameters(Microsoft.AspNetCore.Http.HttpRequest httpRequest, Mockaco.Mock mock) -> System.Threading.Tasks.Task\nMockaco.ScriptContext.Faker.get -> Bogus.Faker\nMockaco.ScriptContext.Global.get -> Mockaco.IGlobalVariableStorage\nMockaco.ScriptContext.Request.get -> Mockaco.ScriptContextRequest\nMockaco.ScriptContext.Request.set -> void\nMockaco.ScriptContext.Response.get -> Mockaco.ScriptContextResponse\nMockaco.ScriptContext.Response.set -> void\nMockaco.ScriptContext.ScriptContext(Mockaco.IFakerFactory fakerFactory, Mockaco.IRequestBodyFactory requestBodyFactory, Mockaco.IGlobalVariableStorage globalVarialeStorage) -> void\nMockaco.ScriptContextRequest\nMockaco.ScriptContextRequest.Body.get -> Newtonsoft.Json.Linq.JToken\nMockaco.ScriptContextRequest.Header.get -> System.Collections.Generic.IReadOnlyDictionary<string, string>\nMockaco.ScriptContextRequest.Query.get -> System.Collections.Generic.IReadOnlyDictionary<string, string>\nMockaco.ScriptContextRequest.Route.get -> System.Collections.Generic.IReadOnlyDictionary<string, string>\nMockaco.ScriptContextRequest.ScriptContextRequest(System.Uri url, System.Collections.Generic.IReadOnlyDictionary<string, string> route, System.Collections.Generic.IReadOnlyDictionary<string, string> query, System.Collections.Generic.IReadOnlyDictionary<string, string> header, Newtonsoft.Json.Linq.JToken body) -> void\nMockaco.ScriptContextRequest.Url.get -> System.Uri\nMockaco.ScriptContextResponse\nMockaco.ScriptContextResponse.Body.get -> Newtonsoft.Json.Linq.JToken\nMockaco.ScriptContextResponse.Header.get -> System.Collections.Generic.IReadOnlyDictionary<string, string>\nMockaco.ScriptContextResponse.ScriptContextResponse(Mockaco.StringDictionary header, Newtonsoft.Json.Linq.JToken body) -> void\nMockaco.StringDictionary\nMockaco.StringDictionary.Add(string key, string value) -> void\nMockaco.StringDictionary.Replace(string key, string value) -> void\nMockaco.StringDictionary.StringDictionary() -> void\nMockaco.StringDictionary.this[string key].get -> string\nMockaco.StringDictionary.this[string key].set -> void\nMockaco.TemplateFileProviderOptions\nMockaco.TemplateFileProviderOptions.Path.get -> string\nMockaco.TemplateFileProviderOptions.Path.set -> void\nMockaco.TemplateFileProviderOptions.TemplateFileProviderOptions() -> void\noverride Mockaco.Mock.ToString() -> string\nstatic Bogus.PhoneNumberExtensions.BrazilianPhoneNumber(this Bogus.DataSets.PhoneNumbers phoneNumbers) -> string\nstatic Microsoft.AspNetCore.Builder.MockacoApplicationBuilder.UseMockaco(this Microsoft.AspNetCore.Builder.IApplicationBuilder app) -> Microsoft.AspNetCore.Builder.IApplicationBuilder\nstatic Microsoft.AspNetCore.Builder.MockacoApplicationBuilder.UseMockaco(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, System.Action<Microsoft.AspNetCore.Builder.IApplicationBuilder> configure) -> Microsoft.AspNetCore.Builder.IApplicationBuilder\nstatic Microsoft.Extensions.DependencyInjection.MockacoServiceCollection.AddMockaco(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection\nstatic Microsoft.Extensions.DependencyInjection.MockacoServiceCollection.AddMockaco(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, Microsoft.Extensions.Configuration.IConfiguration config) -> Microsoft.Extensions.DependencyInjection.IServiceCollection\nstatic Microsoft.Extensions.DependencyInjection.MockacoServiceCollection.AddMockaco(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Mockaco.MockacoOptions> config) -> Microsoft.Extensions.DependencyInjection.IServiceCollection\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Settings/VerificationRouteValueTransformer.cs",
    "content": "﻿namespace Mockaco.Settings\n{\n    using System.Threading.Tasks;\n    using Microsoft.AspNetCore.Http;\n    using Microsoft.AspNetCore.Mvc.Routing;\n    using Microsoft.AspNetCore.Routing;\n\n    internal class VerificationRouteValueTransformer : DynamicRouteValueTransformer\n    {\n        public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)\n        {\n            values[\"controller\"] = \"verify\";\n            values[\"action\"] = \"Get\";\n\n            return ValueTask.FromResult(values);\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Cli/GeneratorRunner.cs",
    "content": "using System;\nusing System.CommandLine;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Mockaco.Templating.Generating.Cli\n{\n    internal class GeneratorRunner\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        public GeneratorRunner(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n        }\n\n        public async Task<int> ExecuteAsync(GeneratingOptions options, IConsole console, CancellationToken cancellationToken)\n        {\n            using var scope = _serviceProvider.CreateScope();\n            await scope.ServiceProvider.GetRequiredService<TemplatesGenerator>().GenerateAsync(options, cancellationToken);\n            return 0;\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/GeneratedTemplate.cs",
    "content": "namespace Mockaco.Templating.Generating\n{\n    internal class GeneratedTemplate : Template\n    {\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/GeneratingOptions.cs",
    "content": "using System;\nusing System.IO;\n\nnamespace Mockaco.Templating.Generating\n{\n    internal class GeneratingOptions\n    {\n        public string Source { get; set; }\n\n        public Uri SourceUri\n        {\n            get\n            {\n                if (Uri.TryCreate(Source, UriKind.Absolute, out Uri uri))\n                {\n                    return uri;\n                }\n                else if (Path.IsPathFullyQualified(Source))\n                {\n                    return new Uri(new Uri(Uri.UriSchemeFile), Source);\n                }\n                else\n                {\n                    throw new ArgumentException(\"Provided Source cannot be converted to Uri\");\n                }\n            }\n        }\n\n        public string Provider { get; set; }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Providers/GeneratedTemplateProviderFactory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Mockaco.Templating.Generating.Providers\n{\n    internal class GeneratedTemplateProviderFactory : IGeneratedTemplateProviderFactory\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        private readonly IDictionary<string, Type> _providersRegistry = new Dictionary<string, Type>\n        {\n            {\"openapi\", typeof(OpenApiTemplateProvider)}\n        };\n\n        public GeneratedTemplateProviderFactory(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n        }\n        \n        public IGeneratedTemplateProvider Create(string providerType)\n        {\n            if (_providersRegistry.ContainsKey(providerType))\n            {\n                return (IGeneratedTemplateProvider)_serviceProvider.GetRequiredService(_providersRegistry[providerType]);\n            }\n\n            throw new NotSupportedException($\"Provider {providerType} is not supported.\");\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Providers/IGeneratedTemplateProvider.cs",
    "content": "using System.Collections.Generic;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Mockaco.Templating.Generating.Providers\n{\n    internal interface IGeneratedTemplateProvider\n    {\n        Task<IEnumerable<GeneratedTemplate>> GetTemplatesAsync(Stream sourceStream, CancellationToken cancellationToken = default);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Providers/IGeneratedTemplateProviderFactory.cs",
    "content": "namespace Mockaco.Templating.Generating.Providers\n{\n    internal interface IGeneratedTemplateProviderFactory\n    {\n        IGeneratedTemplateProvider Create(string providerType);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Providers/OpenApiTemplateProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.OpenApi.Models;\nusing Microsoft.OpenApi.Readers;\nusing Newtonsoft.Json.Linq;\n\nnamespace Mockaco.Templating.Generating.Providers\n{\n    internal class OpenApiTemplateProvider : IGeneratedTemplateProvider\n    {\n        private readonly ILogger _logger;\n\n        public OpenApiTemplateProvider(ILogger<OpenApiTemplateProvider> logger)\n        {\n            _logger = logger;\n        }\n        \n        public Task<IEnumerable<GeneratedTemplate>> GetTemplatesAsync(Stream sourceStream, CancellationToken cancellationToken = default)\n        {\n            \n            var openApiDocument = new OpenApiStreamReader(\n                    new OpenApiReaderSettings\n                    {\n                        ReferenceResolution = ReferenceResolutionSetting.ResolveLocalReferences\n                    }\n                )\n                .Read(sourceStream, out var diagnostic);\n            \n            LogDiagnostics(diagnostic);\n\n            return Task.FromResult(BuildTemplates(openApiDocument));\n        }\n\n        private IEnumerable<GeneratedTemplate> BuildTemplates(OpenApiDocument openApiDocument)\n        {\n            foreach (var path in openApiDocument.Paths)\n            {\n                foreach (var operation in path.Value.Operations)\n                {\n                    var template = new GeneratedTemplate\n                    {\n                        Request = BuildRequest(path, operation),\n                        Response = BuildResponse(operation)\n                    };\n\n                    SetTemplateName(template, operation);\n                    yield return template;\n                }\n            }\n        }\n\n        private void SetTemplateName(GeneratedTemplate template, KeyValuePair<OperationType, OpenApiOperation> operation)\n        {\n            template.Name = operation.Value.OperationId;\n            if (string.IsNullOrWhiteSpace(template.Name))\n            {\n                template.Name = Guid.NewGuid().ToString(\"N\");\n                _logger.LogWarning(\n                    \"The OperationId for request {Method} {Route} hasn't been declared. Using generated template name: {TemplateName}\",\n                    template.Request.Method, template.Request.Route, template.Name);\n            }\n        }\n\n        private ResponseTemplate BuildResponse(KeyValuePair<OperationType,OpenApiOperation> operation)\n        {\n            var responseTemplate = new ResponseTemplate();\n            if (operation.Value.Responses.Any())\n            {\n                var response = operation.Value.Responses.First();\n                responseTemplate.Status = (HttpStatusCode) int.Parse(response.Key);\n                if (response.Value.Content.Any())\n                {\n                    var content = response.Value.Content.First();\n                    responseTemplate.Headers.Add(\"Content-Type\", content.Key);\n                    if (content.Value.Example != null)\n                    {\n                        responseTemplate.Body = JValue.CreateString(content.Value.Example.ToString());\n                    }\n                }\n            }\n            else\n            {\n                responseTemplate.Status = HttpStatusCode.NotFound;\n            }\n            return responseTemplate;\n        }\n\n        private RequestTemplate BuildRequest(KeyValuePair<string,OpenApiPathItem> path, KeyValuePair<OperationType,OpenApiOperation> operation)\n        {\n            return new RequestTemplate\n            {\n                Route = path.Key,\n                Method = Enum.GetName(operation.Key)?.ToUpper()\n            };\n        }\n\n        private void LogDiagnostics(OpenApiDiagnostic diagnostic)\n        {\n            _logger.LogDebug(\"OpenApi specification version: {OpenApiSpecVersion}\", Enum.GetName(diagnostic.SpecificationVersion));\n            foreach (var diagnosticError in diagnostic.Errors)\n            {\n                _logger.LogWarning(\"OpenApi parser diagnostic error: {Error}\", diagnosticError);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/ServiceCollectionExtensions.cs",
    "content": "using Mockaco.Templating.Generating;\nusing Mockaco.Templating.Generating.Cli;\nusing Mockaco.Templating.Generating.Providers;\nusing Mockaco.Templating.Generating.Source;\nusing Mockaco.Templating.Generating.Store;\nusing System.CommandLine;\nusing System.CommandLine.Invocation;\n\nnamespace Microsoft.Extensions.DependencyInjection\n{\n    internal static class ServiceCollectionExtensions\n    {\n        public static IServiceCollection AddTemplatesGenerating(this IServiceCollection services)\n        {\n            services\n                .AddTransient<IGeneratedTemplateStore, GeneratedTemplateStore>()\n                .AddTransient<ISourceContentProvider, SourceContentProviderComposite>()\n                .AddTransient<IGeneratedTemplateProviderFactory, GeneratedTemplateProviderFactory>()\n                .AddTransient<OpenApiTemplateProvider>()\n                .AddTransient<TemplatesGenerator>();\n            \n            services.AddOptions<TemplateStoreOptions>()\n                    .Configure(options =>\n                    {\n                        options.RootDir = \"Mocks\";\n                    })\n                    .BindConfiguration(\"Mockaco:TemplateFileProvider:Path\");\n\n            services.AddTransient<GeneratorRunner>();\n            services.AddTransient(provider =>\n            {\n                var cmd = new Command(\"generate\")\n                {\n                    new Argument<string>(\"source\"),\n                    new Option<string>(new[] { \"--provider\"})\n                    {\n                        IsRequired = true\n                    },\n                    new Option<string>(\"--path\")\n                };\n\n                cmd.Handler = CommandHandler.Create<GeneratingOptions, IConsole, CancellationToken>(\n                    provider.GetRequiredService<GeneratorRunner>().ExecuteAsync);\n                \n                return cmd;\n            });\n            \n            return services;\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Source/HttpContentProvider.cs",
    "content": "using System;\nusing System.IO;\nusing System.Net.Http;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Mockaco.Templating.Generating.Source\n{\n    internal class HttpContentProvider : ISourceContentProvider\n    {\n        public async Task<Stream> GetStreamAsync(Uri sourceUri, CancellationToken cancellationToken)\n        {\n            return await new HttpClient().GetStreamAsync(sourceUri, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Source/ISourceContentProvider.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Mockaco.Templating.Generating.Source\n{\n    internal interface ISourceContentProvider\n    {\n        Task<Stream> GetStreamAsync(Uri sourceUri, CancellationToken cancellationToken);\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Source/LocalFileContentProvider.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Mockaco.Templating.Generating.Source\n{\n    internal class LocalFileContentProvider : ISourceContentProvider\n    {\n        public Task<Stream> GetStreamAsync(Uri sourceUri, CancellationToken cancellationToken)\n        {\n            return Task.FromResult((Stream)File.OpenRead(sourceUri.LocalPath));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Source/SourceContentProviderComposite.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Mockaco.Templating.Generating.Source\n{\n    internal class SourceContentProviderComposite : ISourceContentProvider\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly IDictionary<Predicate<Uri>, Type> _providersRegistry = new Dictionary<Predicate<Uri>, Type>();\n\n        public SourceContentProviderComposite(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n            RegisterDefaultProviders();\n        }\n\n        private void RegisterDefaultProviders()\n        {\n            Register(uri => uri.Scheme.Equals(Uri.UriSchemeFile) || Path.IsPathFullyQualified(uri.OriginalString), typeof(LocalFileContentProvider));\n            Register(uri => uri.Scheme.Equals(Uri.UriSchemeHttp) || uri.Scheme.Equals(Uri.UriSchemeHttps), typeof(HttpContentProvider));\n        }\n\n        private ISourceContentProvider Create(Uri sourceUri)\n        {\n            foreach (var registryItem in _providersRegistry)\n            {\n                var canHandle = registryItem.Key;\n                var providerType = registryItem.Value;\n\n                if (canHandle(sourceUri))\n                {\n                    return (ISourceContentProvider)Activator.CreateInstance(registryItem.Value);\n                }\n            }\n\n            throw new NotSupportedException(\"Specified URI is not supported\");\n        }\n\n        public void Register(Predicate<Uri> canHandle, Type type)\n        {\n            _providersRegistry.Add(canHandle, type);\n        }\n\n        public Task<Stream> GetStreamAsync(Uri sourceUri, CancellationToken cancellationToken)\n        {\n            var specificProvider = Create(sourceUri);\n            return specificProvider.GetStreamAsync(sourceUri, cancellationToken);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Store/GeneratedTemplateStore.cs",
    "content": "using System.Collections.Generic;\nusing System.IO;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace Mockaco.Templating.Generating.Store\n{\n    internal class GeneratedTemplateStore : IGeneratedTemplateStore\n    {\n        private const string FileExtension = \".json\";\n        \n        private readonly IOptions<TemplateStoreOptions> _options;\n        private readonly ILogger _logger;\n\n        public GeneratedTemplateStore(IOptions<TemplateStoreOptions> options, ILogger<GeneratedTemplateStore> logger)\n        {\n            _options = options;\n            _logger = logger;\n        }\n\n        private string RootDir => _options.Value.RootDir;\n\n        public async Task SaveAsync(GeneratedTemplate template, CancellationToken cancellationToken = default)\n        {\n            var templateFileName = GetFileName(template);\n            Directory.CreateDirectory(Path.GetDirectoryName(templateFileName) ?? string.Empty);\n            await File.WriteAllBytesAsync(templateFileName, GetTemplateContent(template), cancellationToken);\n\n            _logger.LogInformation(\"Generated {template} for {method} {route}\", templateFileName, template.Request.Method, template.Request.Route);\n        }\n\n        private byte[] GetTemplateContent(GeneratedTemplate template)\n        {\n            return JsonSerializer.SerializeToUtf8Bytes<Template>(template, new JsonSerializerOptions\n            {\n                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n                WriteIndented = true,\n                DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull\n            });\n        }\n\n        public async Task SaveAsync(IEnumerable<GeneratedTemplate> templates, CancellationToken cancellationToken = default)\n        {\n            foreach (var template in templates)\n            {\n                if (!cancellationToken.IsCancellationRequested)\n                    await SaveAsync(template, cancellationToken);\n                else break;\n            }\n        }\n\n        private string GetFileName(GeneratedTemplate template)\n        {\n            var fileName = template.Name;\n            if (!fileName.EndsWith(FileExtension))\n            {\n                fileName += FileExtension;\n            }\n            \n            return fileName.StartsWith(RootDir) ? fileName : Path.Combine(RootDir, fileName);\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Store/IGeneratedTemplateStore.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Mockaco.Templating.Generating.Store\n{\n    internal interface IGeneratedTemplateStore\n    {\n        Task SaveAsync(GeneratedTemplate template, CancellationToken cancellationToken = default);\n        \n        Task SaveAsync(IEnumerable<GeneratedTemplate> templates, CancellationToken cancellationToken = default);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/Store/TemplateStoreOptions.cs",
    "content": "namespace Mockaco.Templating.Generating.Store\n{\n    internal class TemplateStoreOptions\n    {\n        public string RootDir { get; set; }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Generating/TemplatesGenerator.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\nusing Mockaco.Templating.Generating.Providers;\nusing Mockaco.Templating.Generating.Source;\nusing Mockaco.Templating.Generating.Store;\n\nnamespace Mockaco.Templating.Generating\n{\n    internal class TemplatesGenerator\n    {\n        private readonly ISourceContentProvider _sourceContentProvider;\n        private readonly IGeneratedTemplateProviderFactory _providerFactory;\n        private readonly IGeneratedTemplateStore _templateStore;\n\n        public TemplatesGenerator(ISourceContentProvider sourceContentProvider, IGeneratedTemplateProviderFactory providerFactory, IGeneratedTemplateStore templateStore)\n        {\n            _sourceContentProvider = sourceContentProvider;\n            _providerFactory = providerFactory;\n            _templateStore = templateStore;\n        }\n        \n        public async Task GenerateAsync(GeneratingOptions options, CancellationToken cancellationToken = default)\n        {\n            var sourceStream = await _sourceContentProvider.GetStreamAsync(options.SourceUri, cancellationToken);\n            var templates = await _providerFactory.Create(options.Provider).GetTemplatesAsync(sourceStream, cancellationToken);\n            await _templateStore.SaveAsync(templates, cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/ITemplateTransformer.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal interface ITemplateTransformer\n    {\n        //TODO Improve this abstraction\n        Task<Template> TransformAndSetVariables(IRawTemplate rawTemplate, IScriptContext scriptContext);\n\n        Task<Template> Transform(IRawTemplate rawTemplate, IScriptContext scriptContext);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Models/CallbackTemplate.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing System.Collections.Generic;\n\nnamespace Mockaco\n{\n    internal class CallbackTemplate\n    {\n        public string Method { get; set; }\n\n        public string Url { get; set; }\n\n        public int? Delay { get; set; }\n\n        public int? Timeout { get; set; }\n\n        public bool? Indented { get; set; }\n\n        public IDictionary<string, string> Headers { get; set; }\n\n        public JToken Body { get; set; }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Models/Error.cs",
    "content": "﻿using System;\n\nnamespace Mockaco\n{\n    internal class Error\n    {\n        public string Message { get; }\n\n        public Exception Exception { get; }\n\n        public Error(string message)\n        {\n            Message = message;\n        }\n\n        public Error(Exception exception)\n        {\n            Exception = exception;\n        }\n\n        public Error(string message, Exception exception)\n        {\n            Message = message;\n            Exception = exception;\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Models/IRawTemplate.cs",
    "content": "﻿namespace Mockaco\n{\n    public interface IRawTemplate\n    {\n        string Content { get; }\n\n        string Name { get; }\n\n        string Hash { get; }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Models/Mock.cs",
    "content": "﻿using System.Diagnostics;\n\nnamespace Mockaco\n{\n    [DebuggerDisplay(\"{Method} {Route} ({RawTemplate.Name})\")]\n    public class Mock\n    {\n        public string Method { get; set; }\n\n        public string Route { get; set; }\n\n        public IRawTemplate RawTemplate { get; set; }\n\n        public bool HasCondition { get; set; }\n\n        public Mock(string method, string route, IRawTemplate rawTemplate, bool hasCondition)\n        {\n            Method = method;\n            Route = route;\n            RawTemplate = rawTemplate;\n            HasCondition = hasCondition;\n        }\n\n        public override string ToString()\n        {\n            return $\"{Method} {Route} ({RawTemplate.Name})\";\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Models/RawTemplate.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace Mockaco\n{\n    [DebuggerDisplay(\"{Name}\")]\n    internal class RawTemplate : IRawTemplate\n    {\n        public string Name { get; }\n\n        public string Content { get; }\n\n        public string Hash { get; }\n\n        public RawTemplate(string name, string content)\n        {\n            Name = name;\n            Content = content;\n            Hash = content.ToMD5Hash();\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Models/RequestTemplate.cs",
    "content": "﻿namespace Mockaco\n{\n    internal class RequestTemplate\n    {\n        public string Method { get; set; }\n\n        public string Route { get; set; }\n\n        public bool? Condition { get; set; }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Models/ResponseTemplate.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing System.Collections.Generic;\nusing System.Net;\n\nnamespace Mockaco\n{\n    public class ResponseTemplate\n    {\n        public int? Delay { get; set; }\n\n        public bool? Indented { get; set; }\n\n        public HttpStatusCode Status { get; set; }\n\n        public IDictionary<string, string> Headers { get; set; }\n\n        public JToken Body { get; set; }\n\n        public string File { get; set; }\n\n        public ResponseTemplate()\n        {\n            Headers = new StringDictionary();\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Models/Template.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\n\nnamespace Mockaco\n{\n    internal class Template\n    {\n        public Template()\n        {\n            Callbacks = Enumerable.Empty<CallbackTemplate>();\n        }\n\n        public RequestTemplate Request { get; set; }\n\n        public ResponseTemplate Response { get; set; }\n\n        public CallbackTemplate Callback\n        {\n            get => Callbacks.Count() == 1 ? Callbacks.First() : default;\n            set => Callbacks = new[] { value };\n        }\n\n        public IEnumerable<CallbackTemplate> Callbacks { get; set; }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Providers/ITemplateProvider.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Mockaco\n{\n    internal interface ITemplateProvider\n    {\n        event EventHandler OnChange;\n\n        IEnumerable<IRawTemplate> GetTemplates();\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Providers/TemplateFileProvider.cs",
    "content": "﻿using MAB.DotIgnore;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Caching.Memory;\nusing Microsoft.Extensions.FileProviders;\nusing Microsoft.Extensions.FileProviders.Physical;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.Primitives;\nusing Polly;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading;\n\nnamespace Mockaco\n{\n    internal sealed class TemplateFileProvider : ITemplateProvider, IDisposable\n    {\n        public event EventHandler OnChange;\n\n        private const string MockIgnoreFileName = \".mockignore\";\n        private const string DefaultTemplateSearchPattern = \"*.json\";\n\n        private readonly ILogger<TemplateFileProvider> _logger;\n        \n        private readonly IMemoryCache _memoryCache;\n        private PhysicalFileProvider _fileProvider;\n        private CancellationTokenSource _resetCacheToken = new CancellationTokenSource();\n\n        public TemplateFileProvider(IOptionsMonitor<TemplateFileProviderOptions> options, IWebHostEnvironment webHostEnvironment, IMemoryCache memoryCache, ILogger<TemplateFileProvider> logger)\n        {            \n            _memoryCache = memoryCache;\n            _logger = logger;\n\n            SetMockRootPath(options.CurrentValue.Path);\n            KeepWatchingForFileChanges();\n\n            options.OnChange(options => {\n                SetMockRootPath(options.Path);\n                ResetCacheAndNotifyChange();\n            });\n        }\n\n        private void SetMockRootPath(string path)\n        {\n            try\n            {\n                if(_fileProvider?.Root.Equals(path) == true)\n                {\n                    return;\n                }\n\n                var fullPath = Path.IsPathRooted(path) \n                    ? path \n                    : Path.Combine(Directory.GetCurrentDirectory(), path);\n\n                if (!Directory.Exists(fullPath))\n                {\n                    Directory.CreateDirectory(fullPath);\n                }\n\n                var fileProvider = new PhysicalFileProvider(fullPath, ExclusionFilters.Hidden | ExclusionFilters.System);\n\n                _fileProvider?.Dispose();\n                _fileProvider = fileProvider;\n\n                _logger.LogInformation(\"Mock path: {fullPath}\", fullPath);\n            }            \n            catch (Exception ex)\n            {\n                _logger.LogError(ex, \"Error setting mock root path\");\n            }\n        }\n\n        private void ResetCacheAndNotifyChange()\n        {\n            FlushCache();\n            GetTemplates();\n\n            OnChange?.Invoke(this, EventArgs.Empty);\n\n            KeepWatchingForFileChanges();\n        }\n\n        private void KeepWatchingForFileChanges()\n        {\n            if(_fileProvider == null)\n            {\n                return;\n            }\n\n            var jsonChangeToken = _fileProvider.Watch($\"**/{DefaultTemplateSearchPattern}\");\n            jsonChangeToken.RegisterChangeCallback(TemplateFileModified, default);\n\n            var mockIgnoreChangeToken = _fileProvider.Watch($\"**/*{MockIgnoreFileName}\");\n            mockIgnoreChangeToken.RegisterChangeCallback(TemplateFileModified, default);\n        }\n\n        private void TemplateFileModified(object state)\n        {\n            _logger.LogInformation(\"File change detected\");\n\n            ResetCacheAndNotifyChange();\n        }\n\n        public IEnumerable<IRawTemplate> GetTemplates()\n        {\n            return _memoryCache.GetOrCreate(\n                nameof(TemplateFileProvider),\n                e =>\n                {\n                    e.RegisterPostEvictionCallback(PostEvictionCallback);\n                    e.AddExpirationToken(new CancellationChangeToken(_resetCacheToken.Token));\n\n                    return LoadTemplatesFromDirectory();\n                });\n        }\n\n        private void PostEvictionCallback(object key, object value, EvictionReason reason, object state)\n        {\n            _logger.LogDebug(\"Mock files cache invalidated because of {reason}\", reason);\n        }\n\n        private IEnumerable<IRawTemplate> LoadTemplatesFromDirectory()\n        {\n            if(_fileProvider == null)\n            {\n                yield break;\n            }\n\n            var directory = new DirectoryInfo(_fileProvider.Root);\n\n            foreach (var file in directory.GetFiles(DefaultTemplateSearchPattern, SearchOption.AllDirectories)\n                                .OrderBy(f => f.FullName))\n            {\n                var relativeFilePath = Path.GetRelativePath(_fileProvider.Root, file.FullName);\n\n                if (ShouldIgnoreFile(file))\n                {\n                    _logger.LogDebug(\"{relativeFilePath} ignored using a {MockIgnoreFileName} file\", relativeFilePath, MockIgnoreFileName);\n                    continue;\n                }\n\n                var name = Path.GetRelativePath(directory.FullName, file.FullName);\n                var rawContent = string.Empty;\n\n                var rawTemplate = WrapWithFileExceptionHandling(relativeFilePath, () =>\n                {\n                    using var stream = File.Open(file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read);\n                    using var streamReader = new StreamReader(stream);\n                    rawContent = streamReader.ReadToEnd();\n                    return new RawTemplate(name, rawContent);\n                });\n\n                if (rawTemplate != default)\n                {\n                    yield return rawTemplate;\n                }\n            }\n        }\n\n        private bool ShouldIgnoreFile(FileInfo file)\n        {\n            var mockIgnorePath = Path.Combine(file.DirectoryName, MockIgnoreFileName);\n\n            if (!File.Exists(mockIgnorePath))\n            {\n                return false;\n            }\n\n            var ignores = WrapWithFileExceptionHandling(mockIgnorePath, () =>\n            {\n                return new IgnoreList(mockIgnorePath);\n            });\n\n            if (ignores == default)\n            {\n                return false;\n            }\n\n            return ignores.IsIgnored(file);\n        }\n\n        private T WrapWithFileExceptionHandling<T>(string path, Func<T> action)\n        {\n            void log(Exception ex) => _logger.LogWarning(\"Could not load {path} due to {exceptionType}: {exceptionMessage}\", path, ex.GetType(), ex.Message);\n\n            try\n            {\n                return Policy.Handle<IOException>()\n                        .WaitAndRetry(sleepDurations: new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3) },\n                                      onRetry: (ex, _) => log(ex))\n                        .Execute(action);\n            }\n            catch (Exception ex)\n            {\n                log(ex);\n            }\n\n            return default;\n        }\n\n        private void FlushCache()\n        {\n            if (_resetCacheToken?.IsCancellationRequested == false && _resetCacheToken.Token.CanBeCanceled)\n            {\n                _resetCacheToken.Cancel();\n                _resetCacheToken.Dispose();\n            }\n\n            _resetCacheToken = new CancellationTokenSource();\n        }\n\n        public void Dispose()\n        {\n            _fileProvider?.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/FormRequestBodyStrategy.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Newtonsoft.Json.Linq;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class FormRequestBodyStrategy : IRequestBodyStrategy\n    {\n        public bool CanHandle(HttpRequest httpRequest)\n        {\n            return httpRequest.HasFormContentType;\n        }\n\n        public Task<JToken> ReadBodyAsJson(HttpRequest httpRequest)\n        {\n            return Task.FromResult(JToken.FromObject(httpRequest.Form.ToDictionary(f => f.Key, f => f.Value.ToString())));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/IRequestBodyFactory.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Newtonsoft.Json.Linq;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    public interface IRequestBodyFactory\n    {\n        Task<JToken> ReadBodyAsJson(HttpRequest httpRequest);\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/IRequestBodyStrategy.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Newtonsoft.Json.Linq;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal interface IRequestBodyStrategy\n    {\n        bool CanHandle(HttpRequest httpRequest);\n        Task<JToken> ReadBodyAsJson(HttpRequest httpRequest);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/IRequestMatcher.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal interface IRequestMatcher\n    {\n        Task<bool> IsMatch(HttpRequest httpRequest, Mock mock);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/JsonRequestBodyStrategy.cs",
    "content": "﻿\nusing Microsoft.AspNetCore.Http;\nusing Newtonsoft.Json.Linq;\nusing System.Threading.Tasks;\n\n\nnamespace Mockaco\n{\n    internal class JsonRequestBodyStrategy: IRequestBodyStrategy\n    {\n        public bool CanHandle(HttpRequest httpRequest)\n        {\n            return httpRequest.HasJsonContentType();\n        }\n\n        public async Task<JToken> ReadBodyAsJson(HttpRequest httpRequest)\n        {\n            var body = await httpRequest.ReadBodyStream();\n\n            if (string.IsNullOrWhiteSpace(body))\n            {\n                return new JObject();\n            }\n\n            return JToken.Parse(body);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/RequestBodyFactory.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\nusing Newtonsoft.Json.Linq;\n\nnamespace Mockaco\n{\n    internal class RequestBodyFactory : IRequestBodyFactory\n    {\n        private readonly IEnumerable<IRequestBodyStrategy> _strategies;\n\n        public RequestBodyFactory(IEnumerable<IRequestBodyStrategy> strategies)\n        {\n            _strategies = strategies;\n        }\n\n        public async Task<JToken> ReadBodyAsJson(HttpRequest httpRequest)\n        {\n            if (httpRequest.Body?.CanRead == false)\n            {\n                return new JObject();\n            }\n\n            var selectedStrategy = _strategies.FirstOrDefault(strategy => strategy.CanHandle(httpRequest));\n\n            if (selectedStrategy == null)\n            {\n                return new JObject();\n            }\n\n            return await selectedStrategy.ReadBodyAsJson(httpRequest);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/RequestConditionMatcher.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Newtonsoft.Json;\n\nnamespace Mockaco\n{\n    internal class RequestConditionMatcher : IRequestMatcher\n    {\n        private readonly ITemplateTransformer _templateTransformer;\n        private readonly IFakerFactory _fakerFactory;\n        private readonly IRequestBodyFactory _requestBodyFactory;\n        private readonly IMockacoContext _mockacoContext;\n        private readonly IGlobalVariableStorage _globalVarialeStorage;\n        private readonly ILogger _logger;\n\n        public RequestConditionMatcher(\n            ITemplateTransformer templateTransformer,\n            IFakerFactory fakerFactory,\n            IRequestBodyFactory requestBodyFactory,\n            IMockacoContext mockacoContext,\n            IGlobalVariableStorage globalVariableStoreage,\n            ILogger<RequestConditionMatcher> logger)\n        {\n            _templateTransformer = templateTransformer;\n            _fakerFactory = fakerFactory;\n            _requestBodyFactory = requestBodyFactory;\n            _mockacoContext = mockacoContext;\n            _globalVarialeStorage = globalVariableStoreage;\n            _logger = logger;\n        }\n\n        public async Task<bool> IsMatch(HttpRequest httpRequest, Mock mock)\n        {\n            var conditionMatcherScriptContext = new ScriptContext(_fakerFactory, _requestBodyFactory, _globalVarialeStorage);\n            \n            await AttachRequestToScriptContext(httpRequest.HttpContext, _mockacoContext, conditionMatcherScriptContext);\n\n            if (_mockacoContext.Errors.Any())\n            {\n                return false;\n            }\n\n            await conditionMatcherScriptContext.AttachRouteParameters(httpRequest, mock);\n            try\n            {\n                var template = await _templateTransformer.Transform(mock.RawTemplate, conditionMatcherScriptContext);\n\n                var isMatch = template.Request?.Condition ?? true;\n\n                return isMatch;\n            }\n            catch (Exception ex)\n            {\n                _mockacoContext.Errors.Add(new Error(\"Request condition could not be checked\", ex));\n                _logger.LogError(ex, \"Request condition could not be checked\");\n                return false;\n            }\n        }\n\n        //TODO Remove redundant code\n        private async Task AttachRequestToScriptContext(HttpContext httpContext, IMockacoContext mockacoContext, IScriptContext scriptContext)\n        {\n            try\n            {\n                await scriptContext.AttachRequest(httpContext.Request);\n            }\n            catch (Exception ex)\n            {\n                mockacoContext.Errors.Add(new Error(\"An error occurred while reading request\", ex));\n\n                _logger.LogWarning(ex, \"An error occurred while reading request\");\n\n                return;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/RequestMethodMatcher.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class RequestMethodMatcher : IRequestMatcher\n    {\n        public Task<bool> IsMatch(HttpRequest httpRequest, Mock mock)\n        {\n            if (string.IsNullOrWhiteSpace(mock?.Method))\n            {\n                return Task.FromResult(httpRequest.Method == HttpMethods.Get);\n            }\n\n            var isMatch = httpRequest.Method.Equals(mock.Method, StringComparison.InvariantCultureIgnoreCase);\n\n            return Task.FromResult(isMatch);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/RequestRouteMatcher.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class RequestRouteMatcher : IRequestMatcher\n    {\n        private const string DefaultRoute = \"/\";\n\n        public Task<bool> IsMatch(HttpRequest httpRequest, Mock mock)\n        {\n            var routeMatcher = new RouteMatcher();\n\n            if (string.IsNullOrWhiteSpace(mock?.Route))\n            {\n                return Task.FromResult(routeMatcher.IsMatch(DefaultRoute, httpRequest.Path));\n            }\n\n            return Task.FromResult(routeMatcher.IsMatch(mock.Route, httpRequest.Path));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Request/XmlRequestBodyStrategy.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System.Threading.Tasks;\nusing System.Xml;\n\nnamespace Mockaco\n{\n    internal class XmlRequestBodyStrategy : IRequestBodyStrategy\n    {\n        public bool CanHandle(HttpRequest httpRequest)\n        {\n            return httpRequest.HasXmlContentType();\n        }\n\n        public async Task<JToken> ReadBodyAsJson(HttpRequest httpRequest)\n        {\n            var body = await httpRequest.ReadBodyStream();\n\n            if (string.IsNullOrWhiteSpace(body))\n            {\n                return new JObject();\n            }\n\n            var xmlDocument = new XmlDocument();\n            xmlDocument.LoadXml(body);\n\n            var json = JsonConvert.SerializeXmlNode(xmlDocument);\n\n            return JToken.Parse(json);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Response/BinaryResponseBodyStrategy.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class BinaryResponseBodyStrategy : IResponseBodyStrategy\n    {\n        private readonly IHttpClientFactory _httpClientFactory;\n\n        public BinaryResponseBodyStrategy(IHttpClientFactory httpClientFactory)\n        {\n            _httpClientFactory = httpClientFactory;\n        }\n\n        public bool CanHandle(ResponseTemplate responseTemplate)\n        {\n            responseTemplate.Headers.TryGetValue(HttpHeaders.ContentType, out var contentType);\n\n            return contentType == HttpContentTypes.ApplicationOctetStream || !string.IsNullOrEmpty(responseTemplate.File);\n        }\n\n        public async Task<byte[]> GetResponseBodyBytesFromTemplate(ResponseTemplate responseTemplate)\n        {\n            if (string.IsNullOrEmpty(responseTemplate.File) && string.IsNullOrEmpty(responseTemplate.Body?.ToString()))\n            {\n                return default;\n            }\n\n            if (string.IsNullOrEmpty(responseTemplate.File))\n            {\n                return Encoding.UTF8.GetBytes(responseTemplate.Body.ToString());\n            }\n\n            if (string.IsNullOrEmpty(responseTemplate.Body?.ToString()))\n            {\n                return await GetFileBytes(responseTemplate.File);\n            }\n\n            throw new InvalidOperationException(\"Both attributes \\\"body\\\" and \\\"file\\\" are set in the same response template.\");\n        }\n\n        private async Task<byte[]> GetFileBytes(string path)\n        {\n            if (path.IsRemoteAbsolutePath())\n            {\n                var httpClient = _httpClientFactory.CreateClient();\n\n                var response = await httpClient.GetAsync(path);\n\n                return await response.Content.ReadAsByteArrayAsync();\n            }\n            else\n            {\n                return await File.ReadAllBytesAsync(path);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Response/DefaultResponseBodyStrategy.cs",
    "content": "﻿namespace Mockaco\n{\n    internal class DefaultResponseBodyStrategy : StringResponseBodyStrategy\n    {\n        public override bool CanHandle(ResponseTemplate responseTemplate)\n        {\n            return true;\n        }\n\n        public override string GetResponseBodyStringFromTemplate(ResponseTemplate responseTemplate)\n        {\n            return responseTemplate.Body?.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Response/IResponseBodyFactory.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal interface IResponseBodyFactory\n    {\n        Task<byte[]> GetResponseBodyBytesFromTemplate(ResponseTemplate responseTemplate);\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Response/IResponseBodyStrategy.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal interface IResponseBodyStrategy\n    {\n        bool CanHandle(ResponseTemplate responseTemplate);\n\n        Task<byte[]> GetResponseBodyBytesFromTemplate(ResponseTemplate responseTemplate);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Response/JsonResponseBodyStrategy.cs",
    "content": "﻿using Newtonsoft.Json;\n\nnamespace Mockaco\n{\n    internal class JsonResponseBodyStrategy : StringResponseBodyStrategy\n    {\n        public override bool CanHandle(ResponseTemplate responseTemplate)\n        {\n            responseTemplate.Headers.TryGetValue(HttpHeaders.ContentType, out var contentType);\n\n            return contentType == null || contentType == HttpContentTypes.ApplicationJson;\n        }\n\n        public override string GetResponseBodyStringFromTemplate(ResponseTemplate responseTemplate)\n        {\n            var formatting = responseTemplate.Indented.GetValueOrDefault(true) ? Formatting.Indented : default;\n\n            return responseTemplate.Body?.ToString(formatting);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Response/ResponseBodyFactory.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal class ResponseBodyFactory : IResponseBodyFactory\n    {\n        private readonly IEnumerable<IResponseBodyStrategy> _strategies;\n\n        public ResponseBodyFactory(IEnumerable<IResponseBodyStrategy> strategies)\n        {\n            _strategies = strategies;\n        }\n\n        public Task<byte[]> GetResponseBodyBytesFromTemplate(ResponseTemplate responseTemplate)\n        {\n            if (responseTemplate == default)\n            {\n                return Task.FromResult<byte[]>(default);\n            }\n\n            var selectedStrategy = _strategies.FirstOrDefault(_ => _.CanHandle(responseTemplate));\n\n            return selectedStrategy != null ? selectedStrategy.GetResponseBodyBytesFromTemplate(responseTemplate) : Task.FromResult<byte[]>(default);\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Response/StringResponseBodyStrategy.cs",
    "content": "﻿using System.Text;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal abstract class StringResponseBodyStrategy : IResponseBodyStrategy\n    {\n        public abstract bool CanHandle(ResponseTemplate responseTemplate);\n\n        public Task<byte[]> GetResponseBodyBytesFromTemplate(ResponseTemplate responseTemplate)\n        {\n            var responseBodyStringFromTemplate = GetResponseBodyStringFromTemplate(responseTemplate);\n\n            return Task.FromResult(responseBodyStringFromTemplate == default ? default : Encoding.UTF8.GetBytes(responseBodyStringFromTemplate));\n        }\n\n        public abstract string GetResponseBodyStringFromTemplate(ResponseTemplate responseTemplate);\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Response/XmlResponseBodyStrategy.cs",
    "content": "﻿using System;\nusing System.Text;\nusing System.Xml;\n\nnamespace Mockaco\n{\n    internal class XmlResponseBodyStrategy : StringResponseBodyStrategy\n    {\n        public override bool CanHandle(ResponseTemplate responseTemplate)\n        {\n            responseTemplate.Headers.TryGetValue(HttpHeaders.ContentType, out var contentType);\n\n            return contentType.IsAnyOf(HttpContentTypes.ApplicationXml, HttpContentTypes.TextXml);\n        }\n\n        public override string GetResponseBodyStringFromTemplate(ResponseTemplate responseTemplate)\n        {\n            var settings = new XmlWriterSettings\n            {\n                Indent = responseTemplate.Indented.GetValueOrDefault(true)\n            };\n\n            var stringBuilder = new StringBuilder();\n            using (var writer = XmlWriter.Create(stringBuilder, settings))\n            {\n                var xmlDocument = new XmlDocument();\n                xmlDocument.LoadXml(responseTemplate.Body?.ToString());\n                xmlDocument.WriteContentTo(writer);\n            }\n\n            return stringBuilder.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/IFakerFactory.cs",
    "content": "﻿using Bogus;\nusing System.Collections.Generic;\n\nnamespace Mockaco\n{\n    public interface IFakerFactory\n    {\n        Faker GetDefaultFaker();\n\n        Faker GetFaker(IEnumerable<string> acceptLanguages);     \n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/IGlobalVarialeStorage.cs",
    "content": "﻿namespace Mockaco\n{\n    public interface IGlobalVariableStorage\n    {\n        object this[string name] { get; set; }\n\n        void EnableWriting();\n\n        void DisableWriting();\n\n        void Clear();\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/IScriptContext.cs",
    "content": "﻿using Bogus;\nusing Microsoft.AspNetCore.Http;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    public interface IScriptContext\n    {\n        IGlobalVariableStorage Global { get; }\n\n        Faker Faker { get; }\n\n        ScriptContextRequest Request { get; set; }\n\n        ScriptContextResponse Response { get; set; }\n\n        Task AttachRequest(HttpRequest httpRequest);\n\n        Task AttachRouteParameters(HttpRequest httpRequest, Mock route);\n\n        Task AttachResponse(HttpResponse httpResponse, ResponseTemplate responseTemplate);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/IScriptRunnerFactory.cs",
    "content": "﻿using Microsoft.CodeAnalysis.Scripting;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    internal interface IScriptRunnerFactory\n    {\n        ScriptRunner<TResult> CreateRunner<TContext, TResult>(string code);\n\n        Task<TResult> Invoke<TContext, TResult>(TContext context, string code);\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/LocalizedFakerFactory.cs",
    "content": "﻿using Bogus;\nusing Bogus.Extensions;\nusing Microsoft.Extensions.Logging;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\n\nnamespace Mockaco\n{\n    internal class LocalizedFakerFactory : IFakerFactory\n    {\n        private readonly ILogger<LocalizedFakerFactory> _logger;\n\n        public LocalizedFakerFactory(ILogger<LocalizedFakerFactory> logger)\n        {\n            _logger = logger;\n        }\n\n        public Faker GetDefaultFaker()\n        {\n            var currentCultureBogusLocale = CultureInfo.DefaultThreadCurrentCulture?.ToBogusLocale();\n\n            if (currentCultureBogusLocale != null)\n            {\n                return new Faker(currentCultureBogusLocale);\n            }\n\n            return new Faker();\n        }\n\n        public Faker GetFaker(IEnumerable<string> acceptLanguages)\n        {\n            var supportedBogusLocales = GetSupportedBogusLocales(acceptLanguages);\n\n            var firstSupportedBogusLocale = supportedBogusLocales.FirstOrDefault();\n\n            if (firstSupportedBogusLocale == default)\n            {\n                return GetDefaultFaker();\n            }\n\n            return new Faker(firstSupportedBogusLocale);\n        }\n\n        private IEnumerable<string> GetSupportedBogusLocales(IEnumerable<string> acceptLanguages)\n        {\n            var bogusLocales = new List<string>();\n\n            foreach (var acceptLanguage in acceptLanguages)\n            {\n                try\n                {\n                    var cultureInfo = CultureInfo.GetCultureInfo(acceptLanguage);\n\n                    var bogusLocale = cultureInfo.ToBogusLocale();\n\n                    if (bogusLocale == default)\n                    {\n                        _logger.LogWarning(\"Accept-Language not supported by Bogus: {language}\", acceptLanguage);\n                    }\n\n                    bogusLocales.Add(bogusLocale);\n                }\n                catch (CultureNotFoundException)\n                {\n                    _logger.LogWarning(\"Accept-Language not supported: {language}\", acceptLanguage);\n                }                \n            }\n\n            return bogusLocales;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/ScriptContext.cs",
    "content": "﻿using Bogus;\nusing Microsoft.AspNetCore.Http;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Mockaco\n{\n    public class ScriptContext : IScriptContext\n    {\n        private Uri _uri;\n        private StringDictionary _queryDictionary = new StringDictionary();\n        private StringDictionary _headersDictionary = new StringDictionary();\n        private StringDictionary _routeDictionary = new StringDictionary();\n        private JToken _bodyAsJson;\n        private readonly IFakerFactory _fakerFactory;\n        private readonly IRequestBodyFactory _requestBodyFactory;\n\n        public IGlobalVariableStorage Global { get; }\n\n        public Faker Faker { get; private set; }\n\n        public ScriptContextRequest Request { get; set; }\n\n        public ScriptContextResponse Response { get; set; }\n\n        public ScriptContext(IFakerFactory fakerFactory, IRequestBodyFactory requestBodyFactory, IGlobalVariableStorage globalVarialeStorage)\n        {\n            _fakerFactory = fakerFactory;\n            _requestBodyFactory = requestBodyFactory;\n            Faker = fakerFactory?.GetDefaultFaker();\n            Global = globalVarialeStorage;\n\n            Request = new ScriptContextRequest(\n                default,\n                new StringDictionary(),\n                new StringDictionary(),\n                new StringDictionary(),\n                new JObject());\n\n            Response = new ScriptContextResponse(new StringDictionary(), new JObject());\n        }\n\n        public async Task AttachRequest(HttpRequest httpRequest)\n        {\n            _uri = httpRequest.GetUri();\n            _queryDictionary = httpRequest.Query.ToStringDictionary(k => k.Key, v => v.Value.ToString());\n            _headersDictionary = httpRequest.Headers.ToStringDictionary(k => k.Key, v => v.Value.ToString());\n            _bodyAsJson = await _requestBodyFactory.ReadBodyAsJson(httpRequest);\n\n            Faker = _fakerFactory?.GetFaker(httpRequest.GetAcceptLanguageValues());\n\n            Request = new ScriptContextRequest(url: _uri, route: _routeDictionary, query: _queryDictionary, header: _headersDictionary, body: _bodyAsJson);\n        }\n\n        public Task AttachRouteParameters(HttpRequest httpRequest, Mock mock)\n        {\n            _routeDictionary = httpRequest.GetRouteData(mock)\n                .ToStringDictionary(k => k.Key, v => v.Value.ToString());\n\n            Request = new ScriptContextRequest(url: _uri, route: _routeDictionary, query: _queryDictionary, header: _headersDictionary, body: _bodyAsJson);\n\n            return Task.CompletedTask;\n        }\n\n        public Task AttachResponse(HttpResponse httpResponse, ResponseTemplate responseTemplate)\n        {\n            Response = new ScriptContextResponse(httpResponse.Headers.ToStringDictionary(k => k.Key, v => v.Value.ToString()), responseTemplate?.Body);\n\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/ScriptContextGlobalVariableStorage.cs",
    "content": "﻿using System.Collections.Concurrent;\n\nnamespace Mockaco\n{\n    internal class ScriptContextGlobalVariableStorage : IGlobalVariableStorage\n    {\n        private static readonly ConcurrentDictionary<string, object> _variables = new ConcurrentDictionary<string, object>();\n\n        private bool _canWrite;\n\n        private readonly object _locker = new object();\n\n        public object this[string name]\n        {\n            get\n            {\n                _variables.TryGetValue(name, out var value);\n\n                return value;\n            }\n            set\n            {\n                if (_canWrite)\n                {\n                    _variables.AddOrUpdate(name, value, (name, _) => _variables[name] = value);\n                }\n            }\n        }\n\n        public void Clear()\n        {\n            _variables.Clear();\n        }\n\n        public void DisableWriting()\n        {\n            lock (_locker)\n            {\n                _canWrite = false;\n            }\n        }\n\n        public void EnableWriting()\n        {\n            lock (_locker)\n            {\n                _canWrite = true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/ScriptContextRequest.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Mockaco\n{\n    public class ScriptContextRequest\n    {\n        public Uri Url { get; }\n\n        public IReadOnlyDictionary<string, string> Route { get; }\n\n        public IReadOnlyDictionary<string, string> Query { get; }\n\n        public IReadOnlyDictionary<string, string> Header { get; }\n\n        public JToken Body { get; }\n\n        public ScriptContextRequest(\n            Uri url,\n            IReadOnlyDictionary<string, string> route,\n            IReadOnlyDictionary<string, string> query,\n            IReadOnlyDictionary<string, string> header,\n            JToken body)\n        {\n            Url = url;\n            Route = route;\n            Query = query;\n            Header = header;\n            Body = body;\n        }      \n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/ScriptContextResponse.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing System.Collections.Generic;\n\nnamespace Mockaco\n{\n    public class ScriptContextResponse\n    {\n        public IReadOnlyDictionary<string, string> Header { get; }\n\n        public JToken Body { get; }\n\n        public ScriptContextResponse(StringDictionary header, JToken body)\n        {\n            Header = header;\n            Body = body;\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/Scripting/ScriptRunnerFactory.cs",
    "content": "﻿using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp.Scripting;\nusing Microsoft.CodeAnalysis.Scripting;\nusing Microsoft.Extensions.Caching.Memory;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\n\nnamespace Mockaco\n{\n    internal class ScriptRunnerFactory : IScriptRunnerFactory\n    {\n        private readonly IMemoryCache _cache;\n        private readonly ILogger<ScriptRunnerFactory> _logger;\n        private readonly IOptionsMonitor<MockacoOptions> _options;\n        private MissingResolver _missingResolver;\n\n        public ScriptRunnerFactory(ILogger<ScriptRunnerFactory> logger, IOptionsMonitor<MockacoOptions> options)\n        {\n            _cache = new MemoryCache(new MemoryCacheOptions());\n            _logger = logger;\n            _options = options;\n        }\n\n        public Task<TResult> Invoke<TContext, TResult>(TContext context, string code)\n        {\n            var runner = GetOrCreateRunner<TContext, TResult>(code);\n            \n            return runner.Invoke(context);            \n        }\n\n        private ScriptRunner<TResult> GetOrCreateRunner<TContext, TResult>(string code)\n        {\n            if (_cache.TryGetValue<ScriptRunner<TResult>>(code, out var runner))\n            {\n                _logger.LogTrace(\"Cache hit\");\n\n                return runner;\n            }\n\n            runner = CreateRunner<TContext, TResult>(code);\n\n            _cache.Set(code, runner);\n\n            return runner;\n        }\n\n        public ScriptRunner<TResult> CreateRunner<TContext, TResult>(string code)\n        {\n            var stopWatch = Stopwatch.StartNew();\n\n            if (_missingResolver == null) _missingResolver = new MissingResolver(_cache);\n\n            var scriptOptions = ScriptOptions\n                .Default\n                .WithMetadataResolver(_missingResolver)\n                .AddReferences(\n                    typeof(Bogus.Faker).Assembly,\n                    typeof(ScriptRunnerFactory).Assembly)\n                .AddReferences(_options.CurrentValue.References)\n                .AddImports(\n                    \"System\",\n                    \"System.Linq\",\n                    \"System.Collections.Generic\",\n                    \"System.Text.RegularExpressions\",\n                    typeof(Bogus.Faker).Namespace,\n                    typeof(Bogus.DataSets.System).Namespace,\n                    typeof(ScriptRunnerFactory).Namespace,\n                    \"Newtonsoft.Json\",\n                    \"Newtonsoft.Json.Linq\")\n                .AddImports(_options.CurrentValue.Imports)\n                .WithOptimizationLevel(OptimizationLevel.Release);\n            \n            var script = CSharpScript.Create<TResult>(\n                code,\n                globalsType: typeof(TContext),\n                options: scriptOptions);\n            \n            var runner = script.CreateDelegate();\n            \n            _logger.LogTrace(\"Created runner in {elapsedTime} milliseconds\", stopWatch.ElapsedMilliseconds);\n\n            return runner;\n        }\n\n        /// <summary>\n        /// This class is used to reduce high memory usage during startup\n        /// </summary>\n        private class MissingResolver : MetadataReferenceResolver\n        {\n            public MissingResolver(IMemoryCache cache)\n            {\n                _cache = cache;\n            }\n\n            private readonly IMemoryCache _cache;\n\n            public override bool Equals(object other)\n            {\n                return ScriptMetadataResolver.Default.Equals(other);\n            }\n\n            public override int GetHashCode()\n            {\n                return ScriptMetadataResolver.Default.GetHashCode();\n            }\n\n            public override bool ResolveMissingAssemblies => ScriptMetadataResolver.Default.ResolveMissingAssemblies;\n\n            public override ImmutableArray<PortableExecutableReference> ResolveReference(string reference, string baseFilePath, MetadataReferenceProperties properties)\n            {\n                var key = $\"ResolveReference {reference} {baseFilePath} {properties.GetHashCode()}\";\n\n                return _cache.GetOrCreate(key, (e) =>\n                {\n                    e.SlidingExpiration = TimeSpan.FromSeconds(10);\n                    return ScriptMetadataResolver.Default.ResolveReference(reference, baseFilePath, properties);\n                });\n            }\n\n            public override PortableExecutableReference ResolveMissingAssembly(MetadataReference definition, AssemblyIdentity referenceIdentity)\n            {\n                var key = $\"ResolveMissingAssembly {definition.Display} {referenceIdentity}\";\n\n                return _cache.GetOrCreate(key, (e) =>\n                {\n                    e.SlidingExpiration = TimeSpan.FromSeconds(10);\n                    return ScriptMetadataResolver.Default.ResolveMissingAssembly(definition, referenceIdentity);\n                });\n            }\n        }\n\n    }\n}\n\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/T4/TemplateSegment.cs",
    "content": "﻿// \n// Template.cs\n//  \n// Author:\n//       Mikayla Hutchinson <m.j.hutchinson@gmail.com>\n// \n// Copyright (c) 2009 Novell, Inc. (http://www.novell.com)\n// \n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// \n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n// \n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace Mono.TextTemplating\n{\n    internal interface ISegment\n    {\n        Location StartLocation { get; }\n        Location EndLocation { get; set; }\n        Location TagStartLocation { get; set; }\n    }\n\n    internal class TemplateSegment : ISegment\n    {\n        public TemplateSegment(SegmentType type, string text, Location start)\n        {\n            Type = type;\n            StartLocation = start;\n            Text = text;\n        }\n\n        public SegmentType Type { get; }\n        public string Text { get; }\n        public Location TagStartLocation { get; set; }\n        public Location StartLocation { get; }\n        public Location EndLocation { get; set; }\n    }\n\n    internal class Directive : ISegment\n    {\n        public Directive(string name, Location start)\n        {\n            Name = name;\n            Attributes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);\n            StartLocation = start;\n        }\n\n        public string Name { get; }\n        public Dictionary<string, string> Attributes { get; }\n        public Location TagStartLocation { get; set; }\n        public Location StartLocation { get; }\n        public Location EndLocation { get; set; }\n\n        public string Extract(string key)\n        {\n            if (!Attributes.TryGetValue(key, out var value))\n                return null;\n            Attributes.Remove(key);\n            return value;\n        }\n    }\n\n    internal enum SegmentType\n    {\n        Block,\n        Expression,\n        Content,\n        Helper\n    }\n\n    internal struct Location : IEquatable<Location>\n    {\n        public Location(string fileName, int line, int column)\n            : this()\n        {\n            FileName = fileName;\n            Column = column;\n            Line = line;\n        }\n\n        public int Line { get; }\n        public int Column { get; }\n        public string FileName { get; }\n\n        public static Location Empty => new Location(null, -1, -1);\n\n        public Location AddLine() => new Location(FileName, Line + 1, 1);\n\n        public Location AddCol() => AddCols(1);\n\n        public Location AddCols(int number) => new Location(FileName, Line, Column + number);\n\n        public override string ToString() => $\"[{FileName} ({Line},{Column})]\";\n\n        public bool Equals(Location other)\n        {\n            return other.Line == Line && other.Column == Column && other.FileName == FileName;\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/T4/Tokeniser.cs",
    "content": "﻿// \n// Tokeniser.cs\n//  \n// Author:\n//       Mikayla Hutchinson <m.j.hutchinson@gmail.com>\n// \n// Copyright (c) 2009 Novell, Inc. (http://www.novell.com)\n// \n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// \n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n// \n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nusing System;\n\nnamespace Mono.TextTemplating\n{\n    internal class Tokeniser\n    {\n        private State _nextState;\n        private Location _nextStateLocation;\n        private Location _nextStateTagStartLocation;\n\n        private const char TagStartChar1 = '<';\n        private const char TagStartChar2 = '#';\n        private const char TagEndChar1 = '#';\n        private const char TagEndChar2 = '>';\n\n        public Tokeniser(string fileName, string content)\n        {\n            State = State.Content;\n            Content = content;\n            Location = _nextStateLocation = _nextStateTagStartLocation = new Location(fileName, 1, 1);\n        }\n\n        public bool Advance()\n        {\n            Value = null;\n            State = _nextState;\n            Location = _nextStateLocation;\n            TagStartLocation = _nextStateTagStartLocation;\n            if (_nextState == State.EOF)\n                return false;\n            _nextState = GetNextStateAndCurrentValue();\n            return true;\n        }\n\n        private State GetNextStateAndCurrentValue()\n        {\n            switch (State)\n            {\n                case State.Block:\n                case State.Expression:\n                case State.Helper:\n                    return GetBlockEnd();\n\n                case State.Directive:\n                    return NextStateInDirective();\n\n                case State.Content:\n                    return NextStateInContent();\n\n                case State.DirectiveName:\n                    return GetDirectiveName();\n\n                case State.DirectiveValue:\n                    return GetDirectiveValue();\n\n                case State.EOF:\n                    break;\n\n                default:\n                    throw new InvalidOperationException(\"Unexpected state '\" + State + \"'\");\n            }\n\n            return default(State);\n        }\n\n        private State GetBlockEnd()\n        {\n            var start = Position;\n            for (; Position < Content.Length; Position++)\n            {\n                var c = Content[Position];\n                _nextStateTagStartLocation = _nextStateLocation;\n                _nextStateLocation = _nextStateLocation.AddCol();\n                if (c == '\\r')\n                {\n                    if (Position + 1 < Content.Length && Content[Position + 1] == '\\n')\n                        Position++;\n                    _nextStateLocation = _nextStateLocation.AddLine();\n                }\n                else if (c == '\\n')\n                {\n                    _nextStateLocation = _nextStateLocation.AddLine();\n                }\n                else if (c == TagEndChar2 && Content[Position - 1] == TagEndChar1 && Content[Position - 2] != '\\\\')\n                {\n                    Value = Content.Substring(start, Position - start - 1);\n                    Position++;\n                    TagEndLocation = _nextStateLocation;\n\n                    //skip newlines directly after blocks, unless they're expressions\n                    if (State != State.Expression && (Position += IsNewLine()) > 0)\n                    {\n                        _nextStateLocation = _nextStateLocation.AddLine();\n                    }\n                    return State.Content;\n                }\n            }\n            throw new ParserException(\"Unexpected end of file.\", _nextStateLocation);\n        }\n\n        private State GetDirectiveName()\n        {\n            var start = Position;\n            for (; Position < Content.Length; Position++)\n            {\n                var c = Content[Position];\n                if (!char.IsLetterOrDigit(c))\n                {\n                    Value = Content.Substring(start, Position - start);\n                    return State.Directive;\n                }\n                _nextStateLocation = _nextStateLocation.AddCol();\n            }\n            throw new ParserException(\"Unexpected end of file.\", _nextStateLocation);\n        }\n\n        private State GetDirectiveValue()\n        {\n            var start = Position;\n            int delimiter = '\\0';\n            for (; Position < Content.Length; Position++)\n            {\n                var c = Content[Position];\n                _nextStateLocation = _nextStateLocation.AddCol();\n                if (c == '\\r')\n                {\n                    if (Position + 1 < Content.Length && Content[Position + 1] == '\\n')\n                        Position++;\n                    _nextStateLocation = _nextStateLocation.AddLine();\n                }\n                else if (c == '\\n')\n                    _nextStateLocation = _nextStateLocation.AddLine();\n                if (delimiter == '\\0')\n                {\n                    if (c == '\\'' || c == '\"')\n                    {\n                        start = Position;\n                        delimiter = c;\n                    }\n                    else if (!char.IsWhiteSpace(c))\n                    {\n                        throw new ParserException(\"Unexpected character '\" + c + \"'. Expecting attribute value.\", _nextStateLocation);\n                    }\n                    continue;\n                }\n                if (c == delimiter)\n                {\n                    Value = Content.Substring(start + 1, Position - start - 1);\n                    Position++;\n                    return State.Directive;\n                }\n            }\n            throw new ParserException(\"Unexpected end of file.\", _nextStateLocation);\n        }\n\n        private State NextStateInContent()\n        {\n            var start = Position;\n            for (; Position < Content.Length; Position++)\n            {\n                var c = Content[Position];\n                _nextStateTagStartLocation = _nextStateLocation;\n                _nextStateLocation = _nextStateLocation.AddCol();\n                if (c == '\\r')\n                {\n                    if (Position + 1 < Content.Length && Content[Position + 1] == '\\n')\n                        Position++;\n                    _nextStateLocation = _nextStateLocation.AddLine();\n                }\n                else if (c == '\\n')\n                {\n                    _nextStateLocation = _nextStateLocation.AddLine();\n                }\n                else\n                {\n                    if (c == TagStartChar1 && Position + 2 < Content.Length && Content[Position + 1] == TagStartChar2)\n                    {\n                        TagEndLocation = _nextStateLocation;\n                        var type = Content[Position + 2];\n                        if (type == '@')\n                        {\n                            _nextStateLocation = _nextStateLocation.AddCols(2);\n                            Value = Content.Substring(start, Position - start);\n                            Position += 3;\n                            return State.Directive;\n                        }\n                        if (type == '=')\n                        {\n                            _nextStateLocation = _nextStateLocation.AddCols(2);\n                            Value = Content.Substring(start, Position - start);\n                            Position += 3;\n                            return State.Expression;\n                        }\n                        if (type == '+')\n                        {\n                            _nextStateLocation = _nextStateLocation.AddCols(2);\n                            Value = Content.Substring(start, Position - start);\n                            Position += 3;\n                            return State.Helper;\n                        }\n                        Value = Content.Substring(start, Position - start);\n                        _nextStateLocation = _nextStateLocation.AddCol();\n                        Position += 2;\n                        return State.Block;\n                    }\n                }\n            }\n            //EOF is only valid when we're in content\n            Value = Content.Substring(start);\n            return State.EOF;\n        }\n\n        private int IsNewLine()\n        {\n            var found = 0;\n\n            if (Position < Content.Length && Content[Position] == '\\r')\n            {\n                found++;\n            }\n            if (Position + found < Content.Length && Content[Position + found] == '\\n')\n            {\n                found++;\n            }\n            return found;\n        }\n\n        private State NextStateInDirective()\n        {\n            for (; Position < Content.Length; Position++)\n            {\n                var c = Content[Position];\n                if (c == '\\r')\n                {\n                    if (Position + 1 < Content.Length && Content[Position + 1] == '\\n')\n                        Position++;\n                    _nextStateLocation = _nextStateLocation.AddLine();\n                }\n                else if (c == '\\n')\n                {\n                    _nextStateLocation = _nextStateLocation.AddLine();\n                }\n                else if (char.IsLetter(c))\n                {\n                    return State.DirectiveName;\n                }\n                else if (c == '=')\n                {\n                    _nextStateLocation = _nextStateLocation.AddCol();\n                    Position++;\n                    return State.DirectiveValue;\n                }\n                else if (c == TagEndChar1 && Position + 1 < Content.Length && Content[Position + 1] == TagEndChar2)\n                {\n                    Position += 2;\n                    TagEndLocation = _nextStateLocation.AddCols(2);\n                    _nextStateLocation = _nextStateLocation.AddCols(3);\n\n                    //skip newlines directly after directives\n                    if ((Position += IsNewLine()) > 0)\n                    {\n                        _nextStateLocation = _nextStateLocation.AddLine();\n                    }\n\n                    return State.Content;\n                }\n                else if (!char.IsWhiteSpace(c))\n                {\n                    throw new ParserException(\"Directive ended unexpectedly with character '\" + c + \"'\", _nextStateLocation);\n                }\n                else\n                {\n                    _nextStateLocation = _nextStateLocation.AddCol();\n                }\n            }\n            throw new ParserException(\"Unexpected end of file.\", _nextStateLocation);\n        }\n\n        public State State { get; private set; }\n\n        public int Position { get; private set; }\n\n        public string Content { get; }\n\n        public string Value { get; private set; }\n\n        public Location Location { get; private set; }\n        public Location TagStartLocation { get; private set; }\n        public Location TagEndLocation { get; private set; }\n    }\n\n    internal enum State\n    {\n        Content = 0,\n        Directive,\n        Expression,\n        Block,\n        Helper,\n        DirectiveName,\n        DirectiveValue,\n        Name,\n        EOF\n    }\n\n    internal class ParserException : Exception\n    {\n        public ParserException(string message, Location location)\n            : base(message)\n        {\n            Location = location;\n        }\n\n        public Location Location { get; }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Templating/TemplateTransformer.cs",
    "content": "﻿using Microsoft.Extensions.Logging;\nusing Mockaco.Common;\nusing Mono.TextTemplating;\nusing Newtonsoft.Json;\nusing System.Text;\n\nnamespace Mockaco\n{\n    internal class TemplateTransformer : ITemplateTransformer\n    {\n        private readonly IScriptRunnerFactory _scriptRunnerFactory;\n        private readonly ILogger<TemplateTransformer> _logger;\n\n        public TemplateTransformer(IScriptRunnerFactory scriptRunnerFactory, ILogger<TemplateTransformer> logger)\n        {\n            _scriptRunnerFactory = scriptRunnerFactory;\n            _logger = logger;\n        }\n\n        public async Task<Template> TransformAndSetVariables(IRawTemplate rawTemplate, IScriptContext scriptContext)\n        {\n            scriptContext.Global.EnableWriting();\n\n            var transformedTemplate = await Transform(rawTemplate.Content, scriptContext);\n\n            return JsonConvert.DeserializeObject<Template>(transformedTemplate);\n        }\n\n        public async Task<Template> Transform(IRawTemplate rawTemplate, IScriptContext scriptContext)\n        {\n            scriptContext.Global.DisableWriting();\n\n            var transformedTemplate = await Transform(rawTemplate.Content, scriptContext);\n\n            try\n            {\n                return JsonConvert.DeserializeObject<Template>(transformedTemplate);\n            }\n            catch (JsonReaderException ex)\n            {\n                var jsonEx = new InvalidMockException(\"Generated output is invalid\", ex);\n                jsonEx.Data.Add(\"Output\", transformedTemplate);\n                throw jsonEx;\n            }\n        }\n\n        private async Task<string> Transform(string input, IScriptContext scriptContext)\n        {\n            if (string.IsNullOrWhiteSpace(input))\n            {\n                return input;\n            }\n\n            var tokeniser = new Tokeniser(\"input\", input);\n\n            var output = new StringBuilder();\n\n            while (tokeniser.Advance() && tokeniser.State != State.EOF)\n            {\n                switch (tokeniser.State)\n                {\n                    case State.Content:\n                        output.Append(tokeniser.Value);\n                        break;\n                    case State.Directive:\n                        break;\n                    case State.Expression:\n                        var expressionResult = await Run(tokeniser.Value, scriptContext);\n                        output.Append(expressionResult);\n                        break;\n                    case State.Block:\n                        await Run(tokeniser.Value, scriptContext);\n                        break;\n                    case State.Helper:\n                        break;\n                    case State.DirectiveName:\n                        break;\n                    case State.DirectiveValue:\n                        break;\n                    case State.Name:\n                        break;\n                    case State.EOF:\n                        break;\n                    default:\n                        throw new InvalidOperationException();\n                }\n            }\n\n            return output.ToString();\n        }\n\n        private async Task<object> Run(string code, IScriptContext scriptContext)\n        {\n            try\n            {\n                var result = await _scriptRunnerFactory.Invoke<IScriptContext, object>(scriptContext, code);\n\n                _logger.LogDebug(\"Processed script {code} with result {result}\", code, result);\n\n                return result;\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex, \"Processed script {code} with error\", code);\n                throw;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Mockaco.AspNetCore/Verifyer/VerifyerExtensions.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.Caching.Memory;\n\nnamespace Mockaco.Verifyer\n{\n    internal static class VerifyerExtensions\n    {\n        public static IResult Verify([FromQuery] string route, [FromServices] IMemoryCache cache)\n        {\n            var requestHappened = cache.TryGetValue($\"{nameof(RequestMatchingMiddleware)} {route}\", out var mock);\n            if (requestHappened)\n            {\n                return Results.Ok(mock);\n            }\n\n            return Results.NotFound();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Mockaco.AspNetCore/WarmUps/MockProviderWarmUp.cs",
    "content": "﻿using Microsoft.Extensions.Hosting;\n\nnamespace Mockaco\n{\n    internal sealed class MockProviderWarmUp : IHostedService\n    {\n        private readonly IHostApplicationLifetime _hostApplicationLifetime;\n        private readonly IMockProvider _mockProvider;\n\n        public MockProviderWarmUp(IHostApplicationLifetime hostApplicationLifetime, IMockProvider mockProvider)\n        {\n            _hostApplicationLifetime = hostApplicationLifetime;\n            _mockProvider = mockProvider;\n        }\n\n        public Task StartAsync(CancellationToken cancellationToken)\n        {\n            _hostApplicationLifetime.ApplicationStarted.Register(OnStarted);\n\n            return Task.CompletedTask;\n        }\n\n        public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;\n\n        private void OnStarted()\n        {\n            _mockProvider.WarmUp();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Common/StringDictionaryTest.cs",
    "content": "using Xunit;\nusing Mockaco;\nusing FluentAssertions;\n\npublic class StringDictionaryTests\n{\n    [Fact]\n    public void Add_WhenKeyNotExists_AddsKeyValue()\n    {\n        var dictionary = new StringDictionary();\n        var key = \"testKey\";\n        var value = \"testValue\";\n        dictionary.Add(key, value);\n        dictionary.ContainsKey(key).Should().BeTrue();\n        dictionary[key].Should().Be(value);\n    }\n\n    [Fact]\n    public void Add_WhenKeyExists_ReplacesValue()\n    {\n        var dictionary = new StringDictionary();\n        var key = \"testKey\";\n        var initialValue = \"initialValue\";\n        var newValue = \"newValue\";\n        dictionary.Add(key, initialValue);\n        dictionary.Add(key, newValue);\n        dictionary.ContainsKey(key).Should().BeTrue();\n        dictionary[key].Should().Be(newValue);\n    }\n\n    [Fact]\n    public void Replace_WhenKeyNotExists_AddsKeyValue()\n    {\n        var dictionary = new StringDictionary();\n        var key = \"testKey\";\n        var value = \"testValue\";\n        dictionary.Replace(key, value);\n        dictionary.ContainsKey(key).Should().BeTrue();\n        dictionary[key].Should().Be(value);\n    }\n\n    [Fact]\n    public void Replace_WhenKeyExists_ReplacesValue()\n    {\n        var dictionary = new StringDictionary();\n        var key = \"testKey\";\n        var initialValue = \"initialValue\";\n        var newValue = \"newValue\";\n        dictionary.Add(key, initialValue);\n        dictionary.Replace(key, newValue);\n        dictionary.ContainsKey(key).Should().BeTrue();\n        dictionary[key].Should().Be(newValue);\n    }\n\n    [Fact]\n    public void Indexer_Get_WhenKeyNotExists_ReturnsEmptyString()\n    {\n        var dictionary = new StringDictionary();\n        var key = \"testKey\";\n        var value = dictionary[key];\n        value.Should().BeEmpty();\n    }\n\n    [Fact]\n    public void Indexer_Set_UpdatesValue()\n    {\n        var dictionary = new StringDictionary();\n        var key = \"testKey\";\n        var value = \"testValue\";\n        dictionary[key] = value;\n        dictionary[key].Should().Be(value);\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Extensions/EnumerableExtensionTests.cs",
    "content": "namespace Mockaco.Tests.Extensions;\n\npublic class EnumerableExtensionTests\n{\n    [Theory]\n    [MemberData(nameof(Data))]\n    public void Select_Random_IEnumerables(List<object> source)\n    {\n        IEnumerable<object> enummerables = source;\n\n        object selected = enummerables.Random();\n\n        Assert.Contains(selected, source);\n    }\n\n    public static IEnumerable<object[]> Data()\n    {\n        yield return new object[] { new List<object> { 1, 2, 3 } };\n        yield return new object[] { new List<object> { \"a\", \"b\", \"c\" } };\n        yield return new object[] { new List<object> { \"a1\", \"c2\" } };\n    }\n}"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Extensions/StringExtensionsTests.cs",
    "content": "namespace Mockaco.AspNetCore.Tests.Extensions;\n\npublic class StringExtensionsTests\n{\n    [Fact]\n    public void Returns_False_For_Null_String()\n    {\n        string? stringValue = null;\n        Assert.False(stringValue.IsRemoteAbsolutePath());\n    }\n\n    [Fact]\n    public void Returns_False_For_Empty_String()\n    {\n        string? stringValue = \"\";\n        Assert.False(stringValue.IsRemoteAbsolutePath());\n    }\n\n    [Fact]\n    public void Returns_False_For_Relative_Path()\n    {\n        string? stringValue = \".\";\n        Assert.False(stringValue.IsRemoteAbsolutePath());\n    }\n\n    [Fact]\n    public void Returns_True_For_Absolute_Path()\n    {\n        string? stringValue = \"http://www.github.com\";\n        Assert.True(stringValue.IsRemoteAbsolutePath());\n    }\n}"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Middlewares/CallbackMiddlewareTest.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace Mockaco.Tests.Middlewares\n{\n    public class CallbackMiddlewareTest\n    {\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Middlewares/ErrorHandlingMiddlewareTest.cs",
    "content": "﻿using FluentAssertions;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Moq;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Mockaco.Tests.Middlewares\n{\n    public class ErrorHandlingMiddlewareTest\n    {\n        private readonly IOptionsSnapshot<MockacoOptions> _statusCodeOptions;\n        private readonly IMockProvider _mockProvider;\n        private readonly ILogger<ErrorHandlingMiddleware> _logger;\n        private readonly ErrorHandlingMiddleware _middleware;\n        private readonly RequestDelegate _next;\n\n        public ErrorHandlingMiddlewareTest()\n        {\n            _next = Moq.Mock.Of<RequestDelegate>();\n            _statusCodeOptions = Moq.Mock.Of<IOptionsSnapshot<MockacoOptions>>(o => o.Value == new MockacoOptions());\n            _mockProvider = Moq.Mock.Of<IMockProvider>();\n            _logger = Moq.Mock.Of<ILogger<ErrorHandlingMiddleware>>();\n            _middleware = new ErrorHandlingMiddleware(_next);\n        }\n\n        [Fact]\n        public async Task Writes_Unhandled_Exceptions_Thrown_In_Inner_Middlewares_As_Errors_In_Response_Body()\n        {\n            DefaultHttpContext httpContext = GetHttpContextForTest();\n\n            var anyException = new InvalidOperationException(\"Any error\");\n            Moq.Mock.Get(_next).Setup(n => n.Invoke(It.IsAny<HttpContext>())).ThrowsAsync(anyException);\n\n            var mockacoContext = Moq.Mock.Of<IMockacoContext>(c => c.Errors == new List<Error>());\n\n            await _middleware.Invoke(httpContext, mockacoContext, _statusCodeOptions, _mockProvider, _logger);\n\n            var body = await ReadResponseBody(httpContext);\n\n            var bodyAsJToken = JToken.Parse(body);\n\n            bodyAsJToken.Should().NotBeNullOrEmpty();\n            bodyAsJToken.SelectToken(\"$[0].Exception.Type\").ToString().Should().Be(anyException.GetType().Name);\n            bodyAsJToken.SelectToken(\"$[0].Exception.Message\").ToString().Should().Be(anyException.Message);\n            httpContext.Response.StatusCode.Should().Be(501);\n            httpContext.Response.ContentType.Should().Be(\"application/json\");\n        }\n\n        [Fact]\n        public async Task Writes_Mockaco_Context_Errors_To_Response_Body()\n        {\n            var httpContext = GetHttpContextForTest();\n\n            var anyError = new Error(\"any message\");\n\n            var mockacoContext = Moq.Mock.Of<IMockacoContext>(c => c.Errors == new List<Error> { anyError });\n\n            await _middleware.Invoke(httpContext, mockacoContext, _statusCodeOptions, _mockProvider, _logger);\n\n            var body = await ReadResponseBody(httpContext);\n\n            var bodyAsJToken = JToken.Parse(body);\n\n            bodyAsJToken.Should().NotBeNullOrEmpty();\n\n            bodyAsJToken.SelectToken(\"$[0].Message\").ToString().Should().Be(anyError.Message);\n\n            httpContext.Response.StatusCode.Should().Be(501);\n            httpContext.Response.ContentType.Should().Be(\"application/json\");\n        }\n\n        [Fact]\n        public async Task Includes_MockProvider_Errors_To_Response_Body_When_Any_Error_Occurs()\n        {\n            const string providerMessage = \"any provider message\";\n            var httpContext = GetHttpContextForTest();\n\n            Moq.Mock.Get(_mockProvider).Setup(m => m.GetErrors()).Returns(new[] { (\"any/mock\", providerMessage) }).Verifiable();\n\n            var errors = new List<Error> { new Error(\"any message\") };\n            var mockacoContext = Moq.Mock.Of<IMockacoContext>(c => c.Errors == errors);\n\n            await _middleware.Invoke(httpContext, mockacoContext, _statusCodeOptions, _mockProvider, _logger);\n\n            Moq.Mock.Verify(Moq.Mock.Get(_mockProvider));\n\n            errors.Should().HaveCount(2);\n            errors.Any(e => e.Message.Contains(providerMessage)).Should().BeTrue();\n        }\n\n        private static DefaultHttpContext GetHttpContextForTest()\n        {\n            var httpContext = new DefaultHttpContext();\n\n            httpContext.Response.Body = new MemoryStream();\n\n            return httpContext;\n        }\n\n        private static async Task<string> ReadResponseBody(DefaultHttpContext httpContext)\n        {\n            httpContext.Response.Body.Seek(0, SeekOrigin.Begin);\n\n            var streamReader = new StreamReader(httpContext.Response.Body);\n\n            var body = await streamReader.ReadToEndAsync();\n\n            return body;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Middlewares/RequestMatchingMiddlewareTest.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Caching.Memory;\nusing Microsoft.Extensions.Options;\nusing Xunit;\n\nnamespace Mockaco.Tests.Middlewares\n{\n    public class RequestMatchingMiddlewareTest\n    {\n        private readonly RequestMatchingMiddleware _middleware;\n\n        public RequestMatchingMiddlewareTest()\n        {\n            var next = Moq.Mock.Of<RequestDelegate>();\n            var logger = Moq.Mock.Of<ILogger<RequestMatchingMiddleware>>();\n            _middleware = new RequestMatchingMiddleware(next, logger);\n        }\n\n        [Fact]\n        public async Task Attaches_Request_Parameters_To_Be_Accessible_Via_ScriptContext()\n        {\n            var expectedUri = new Uri(\"http://127.0.0.1\");\n            var expectedBody = Encoding.UTF8.GetBytes(\"TestBodyData\");\n\n            var httpRequest = new Moq.Mock<HttpRequest>();\n            httpRequest.Setup(h => h.Scheme).Returns(expectedUri.Scheme);\n            httpRequest.Setup(h => h.Host).Returns(new HostString(expectedUri.Host));\n            httpRequest.Setup(h => h.Query).Returns(new QueryCollection());\n            httpRequest.Setup(h => h.Headers).Returns(new HeaderDictionary());\n\n            using (var bodyStream = new MemoryStream(expectedBody))\n            {\n                httpRequest.Setup(h => h.Body).Returns(bodyStream);\n\n                var httpContext = Moq.Mock.Of<HttpContext>(c => c.Request == httpRequest.Object && c.Connection.RemoteIpAddress == IPAddress.Loopback);\n                var mockacoContext = Moq.Mock.Of<IMockacoContext>(c => c.Errors == new List<Error>());\n\n                var scriptContext = new Moq.Mock<IScriptContext>();\n                scriptContext.Setup(c => c.AttachRequest(httpRequest.Object)).Verifiable();\n\n                var mockProvider = new Moq.Mock<IMockProvider>();\n                mockProvider.Setup(p => p.GetMocks()).Returns(new List<Mock>());\n\n                var templateTransformer = Moq.Mock.Of<ITemplateTransformer>();\n                var requestMatchers = Moq.Mock.Of<IEnumerable<IRequestMatcher>>();\n                var memoryCache = Moq.Mock.Of<IMemoryCache>();\n                var options = Moq.Mock.Of<IOptions<MockacoOptions>>();\n\n                await _middleware.Invoke(httpContext, mockacoContext, scriptContext.Object, mockProvider.Object, templateTransformer, requestMatchers, memoryCache, options);\n\n                Moq.Mock.Verify(scriptContext);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Middlewares/ResponseDelayMiddlewareTest.cs",
    "content": "﻿using FluentAssertions;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Mockaco.Tests.Middlewares\n{\n    public class ResponseDelayMiddlewareTest\n    {\n        private RequestDelegate _next;\n        private IMockacoContext _mockacoContext;\n        private ResponseDelayMiddleware _middleware;\n        private HttpContext _httpContext;\n        private ILogger<ResponseDelayMiddleware> _logger;\n\n        public ResponseDelayMiddlewareTest()\n        {\n            _next = Moq.Mock.Of<RequestDelegate>();\n            _mockacoContext = Moq.Mock.Of<IMockacoContext>();\n            _middleware = new ResponseDelayMiddleware(_next);\n            _httpContext = Moq.Mock.Of<HttpContext>();\n            _logger = Moq.Mock.Of<ILogger<ResponseDelayMiddleware>>();\n        }\n\n        [Theory]\n        [InlineData(1000, 1000)]\n        [InlineData(2500, 2500)]\n        [InlineData(3000, 3000)]\n        public async Task Modifies_Request_Duration(int delay, int expectedDelay)\n        {\n            Moq.Mock.Get(_mockacoContext).Setup(c => c.TransformedTemplate)\n                .Returns(new Template() { Response = new ResponseTemplate() { Delay = delay } });\n\n            var stopwatch = Stopwatch.StartNew();\n\n            await _middleware.Invoke(_httpContext, _mockacoContext, _logger);\n\n            stopwatch.Stop();\n\n            stopwatch.ElapsedMilliseconds.Should().BeCloseTo(expectedDelay, 100);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Middlewares/ResponseMockingMiddlewareTest.cs",
    "content": "﻿using FluentAssertions;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Options;\nusing Moq;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Mockaco.Tests.Middlewares\n{\n    public class ResponseMockingMiddlewareTest\n    {\n        private readonly ResponseMockingMiddleware _middleware;\n\n        public ResponseMockingMiddlewareTest()\n        {\n            var next = Moq.Mock.Of<RequestDelegate>();\n            _middleware = new ResponseMockingMiddleware(next);\n        }\n\n        [Fact]\n        public async Task Produces_Response_With_Default_Http_Status_When_Ommited_In_Template()\n        {\n            var defaultHttpStatusCode = HttpStatusCode.OK;\n            var actualHttpStatusCode = default(int);\n\n            var httpResponse = new Mock<HttpResponse>();            \n            httpResponse.SetupSet(r => r.StatusCode = It.IsAny<int>()).Callback<int>(value => actualHttpStatusCode = value);\n            httpResponse.Setup(r => r.Body).Returns(Moq.Mock.Of<Stream>());\n\n            var httpContext = Moq.Mock.Of<HttpContext>(c => c.Response == httpResponse.Object);\n\n            var templateWithOmmitedStatus = Moq.Mock.Of<Template>(t => t.Response == Moq.Mock.Of<ResponseTemplate>());\n            var mockacoContext = Moq.Mock.Of<IMockacoContext>(c => c.TransformedTemplate == templateWithOmmitedStatus);\n\n            var scriptContext = Moq.Mock.Of<IScriptContext>();\n            var responseBodyFactory = Moq.Mock.Of<IResponseBodyFactory>();\n\n            var optionsWithDefaulHttpStatusCode = Moq.Mock.Of<MockacoOptions>(o => o.DefaultHttpStatusCode == defaultHttpStatusCode);\n            var mockacoOptionsSnapshot = Moq.Mock.Of<IOptionsSnapshot<MockacoOptions>>(s => s.Value == optionsWithDefaulHttpStatusCode);\n\n            await _middleware.Invoke(httpContext, mockacoContext, scriptContext, responseBodyFactory, mockacoOptionsSnapshot);\n\n            actualHttpStatusCode.Should()\n                .Be((int)defaultHttpStatusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Mockaco.AspNetCore.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net6.0</TargetFramework>\n\t\t<RootNamespace>Mockaco.AspNetCore.Tests</RootNamespace>\n\t\t<ImplicitUsings>enable</ImplicitUsings>\n\t\t<Nullable>enable</Nullable>\n\n\t\t<IsPackable>false</IsPackable>\n\t\t<IsTestProject>true</IsTestProject>\n\t</PropertyGroup>\n\n\t<ItemGroup>\n\t\t<PackageReference Include=\"FluentAssertions\" Version=\"6.11.0\" />\n\t\t<PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.6.2\" />\n\t\t<PackageReference Include=\"Moq\" Version=\"4.18.4\" />\n\t\t<PackageReference Include=\"Testcontainers\" Version=\"3.2.0\" />\n\t\t<PackageReference Include=\"xunit\" Version=\"2.4.2\" />\n\t\t<PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.5\">\n\t\t\t<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n\t\t\t<PrivateAssets>all</PrivateAssets>\n\t\t</PackageReference>\n\t\t<PackageReference Include=\"coverlet.collector\" Version=\"6.0.0\">\n\t\t\t<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n\t\t\t<PrivateAssets>all</PrivateAssets>\n\t\t</PackageReference>\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t  <ProjectReference Include=\"..\\..\\src\\Mockaco.AspNetCore\\Mockaco.AspNetCore.csproj\" />\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<Content Include=\"Templating\\Response\\mockaco.jpg\">\n\t\t\t<CopyToOutputDirectory>Always</CopyToOutputDirectory>\n\t\t</Content>\n\t</ItemGroup>\n\n\t<ItemGroup>\n\t\t<None Update=\"Templating\\Transforms_Plain_Json_Template.json\">\n\t\t\t<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n\t\t\t<CopyToOutputDirectory>Always</CopyToOutputDirectory>\n\t\t</None>\n\t\t<None Update=\"Templating\\Transforms_Scripted_Json_Template.json\">\n\t\t\t<CopyToOutputDirectory>Always</CopyToOutputDirectory>\n\t\t\t<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n\t\t</None>\n\t</ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Request/JsonRequestBodyStrategyTest.cs",
    "content": "﻿using FluentAssertions;\nusing Microsoft.AspNetCore.Http;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.IO;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Mockaco.Tests.Templating.Request\n{\n    public sealed class JsonRequestBodyStrategyTest : IDisposable\n    {\n        private MemoryStream _bodyStream;\n\n        [Theory]\n        [InlineData(\"[{\\\"A\\\":\\\"XYZ\\\",\\\"B\\\":\\\"99999999\\\"}]\", \"$[0].A\", JTokenType.Array, \"XYZ\")]\n        [InlineData(\"{\\\"A\\\":\\\"XYZ\\\",\\\"B\\\":\\\"99999999\\\"}\", \"$.A\", JTokenType.Object, \"XYZ\")]\n        [InlineData(\"\\\"XYZ\\\"\", \"$\", JTokenType.String, \"XYZ\")]\n        [InlineData(\"null\", \"$\", JTokenType.Null, \"\")]\n        [InlineData(\"\", \"$\", JTokenType.Object, \"{}\")]\n        public async Task Attaches_Request_With_Json_Body_With_Type(\n            string givenBody,\n            string jsonPath,\n            JTokenType expectedJsonType,\n            string expectedJsonValue)\n        {\n            var httpRequest = PrepareHttpRequest(givenBody);\n\n            var bodyStrategy = new JsonRequestBodyStrategy();\n            var actualBodyAsJson = await bodyStrategy.ReadBodyAsJson(httpRequest.Object);\n\n            actualBodyAsJson.Type\n                .Should()\n                .Be(expectedJsonType);\n\n            actualBodyAsJson.SelectToken(jsonPath).ToString()\n                .Should()\n                .Be(expectedJsonValue);\n        }\n\n        [Theory]\n        [InlineData(\"x\")]\n        [InlineData(\"<>\")]\n        [InlineData(\"{ ab }\")]\n        public void Throws_Exception_When_Request_Has_Invalid_Json(string givenBody)\n        {\n            var httpRequest = PrepareHttpRequest(givenBody);\n\n            var bodyStrategy = new JsonRequestBodyStrategy();\n\n            bodyStrategy.Invoking(async _ => await _.ReadBodyAsJson(httpRequest.Object))\n                .Should()\n                .ThrowAsync<JsonReaderException>();\n        }\n\n        [Theory]\n        [InlineData(\"application/json\", true)]\n        [InlineData(\"application/json; charset=utf-8\", true)]\n        [InlineData(\"application/x-www-form-urlencoded\", false)]\n        [InlineData(\"multipart/form-data\", false)]\n        [InlineData(\"application/xml\", false)]\n        public void Can_Handle_Specific_ContentType(string givenContenType, bool expectedCanHandle)\n        {\n            var httpRequest = PrepareHttpRequest(\"{}\", givenContenType);\n\n            var bodyStrategy = new JsonRequestBodyStrategy();\n            var actualCanHandle = bodyStrategy.CanHandle(httpRequest.Object);\n\n            actualCanHandle\n                .Should()\n                .Be(expectedCanHandle);\n        }\n\n        private Moq.Mock<HttpRequest> PrepareHttpRequest(string givenBody, string givenContentType = \"application/json\")\n        {\n            var httpRequest = new Moq.Mock<HttpRequest>(Moq.MockBehavior.Strict);\n            var bodyBuffer = Encoding.UTF8.GetBytes(givenBody);\n            _bodyStream = new MemoryStream(bodyBuffer);\n\n            httpRequest.Setup(h => h.ContentType).Returns(givenContentType);\n            httpRequest.Setup(h => h.Body).Returns(_bodyStream);\n\n            return httpRequest;\n        }\n\n        public void Dispose() => _bodyStream.Dispose();\n    }\n}"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Request/RequestConditionMatcherTest.cs",
    "content": "﻿using FluentAssertions;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Moq;\nusing System.Net;\n\nnamespace Mockaco.AspNetCore.Tests.Templating.Request\n{\n    public sealed class RequestConditionMatcherTest\n    {\n        private readonly IGlobalVariableStorage _globalVariableStorage;\n        private readonly ITemplateTransformer _templateTransformer;\n        private readonly IFakerFactory _fakerFactory;\n        private readonly ILogger<RequestConditionMatcher> _logger;\n        private readonly IRequestBodyFactory _requestBodyFactory;\n        private readonly IMockacoContext _mockacoContext;\n\n        public RequestConditionMatcherTest()\n        {\n            _templateTransformer = Moq.Mock.Of<ITemplateTransformer>();\n            _fakerFactory = Moq.Mock.Of<IFakerFactory>();\n            _requestBodyFactory = Moq.Mock.Of<IRequestBodyFactory>();\n            _mockacoContext = Moq.Mock.Of<IMockacoContext>();\n            _globalVariableStorage = Moq.Mock.Of<IGlobalVariableStorage>();\n            _logger = Moq.Mock.Of<ILogger<RequestConditionMatcher>>();\n        }\n\n        [Fact]\n        public async Task Condition_Does_Not_Match_On_Script_Error()\n        {\n            Moq.Mock.Get(_templateTransformer)\n                .Setup(n => n.Transform(It.IsAny<IRawTemplate>(), It.IsAny<IScriptContext>()))\n                .ThrowsAsync(new NotImplementedException());\n\n            Moq.Mock.Get(_mockacoContext).Setup(c => c.Errors).Returns(new List<Error>());\n\n            var conditionMatcher = new RequestConditionMatcher(\n                _templateTransformer, _fakerFactory, _requestBodyFactory, _mockacoContext, _globalVariableStorage, _logger);\n\n            var httpRequest = new Mock<HttpRequest>();\n            httpRequest.Setup(h => h.HttpContext)\n                .Returns(Moq.Mock.Of<HttpContext>(c => c.Request == httpRequest.Object));\n\n            var rawTemplate = Moq.Mock.Of<IRawTemplate>();\n            Moq.Mock.Get(rawTemplate).Setup(r => r.Content).Returns(@\"\");\n\n            var mock = new Mock(\"GET\", \"/ping\", rawTemplate, true);\n\n            var isMatch = await conditionMatcher.IsMatch(httpRequest.Object, mock);\n\n            isMatch.Should().Be(false);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Response/BinaryResponseBodyStrategyTest.cs",
    "content": "﻿using FluentAssertions;\nusing System;\nusing System.IO;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Mockaco.Tests.Templating.Response\n{\n    public class BinaryResponseBodyStrategyTest\n    {\n        private readonly BinaryResponseBodyStrategy _strategy;\n\n        public BinaryResponseBodyStrategyTest()\n        {\n            var httpClientFactory = Moq.Mock.Of<IHttpClientFactory>();\n\n            _strategy = new BinaryResponseBodyStrategy(httpClientFactory);\n        }\n\n        [Fact]\n        public void Can_Handle_Templates_With_Response_File_Attribute()\n        {\n            var responseTemplate = new ResponseTemplate { File = \"somefile.bin\" };\n\n            _strategy.CanHandle(responseTemplate)\n                .Should()\n                .BeTrue();\n        }\n\n        [Fact]\n        public void Can_Handle_Templates_With_Response_Body_Attribute_And_Application_Octet_Stream_Content_Type()\n        {\n            var responseTemplate = new ResponseTemplate\n            {\n                Headers = new StringDictionary { { HttpHeaders.ContentType, HttpContentTypes.ApplicationOctetStream } },\n                Body = \"randomdata\"\n            };\n\n            _strategy.CanHandle(responseTemplate)\n                .Should()\n                .BeTrue();\n        }\n\n        [Fact]\n        public void Can_Not_Handle_Templates_With_Response_Body_Attribute_And_No_Content_Type()\n        {\n            var responseTemplate = new ResponseTemplate { Body = \"randomdata\" };\n\n            _strategy.CanHandle(responseTemplate)\n                .Should()\n                .BeFalse();\n        }\n\n        [Fact]\n        public async Task Returns_Response_For_Binary_File()\n        {\n            const string responseFilePath = \"Templating/Response/mockaco.jpg\";\n\n            var responseTemplate = new ResponseTemplate { File = responseFilePath };\n\n            var bodyBytes = await _strategy.GetResponseBodyBytesFromTemplate(responseTemplate);\n\n            var fileBytes = await File.ReadAllBytesAsync(responseFilePath);\n\n            bodyBytes.Should()\n                .BeEquivalentTo(fileBytes);\n        }\n\n        [Fact]\n        public async Task Throws_When_Both_Body_And_File_Attributes_Are_Set()\n        {\n            var responseTemplate = new ResponseTemplate { File = \"somefile.bin\", Body = \"randomdata\" };\n\n            Func<Task> action = async () => await _strategy.GetResponseBodyBytesFromTemplate(responseTemplate);\n\n            await action.Should()\n                .ThrowAsync<InvalidOperationException>();\n        }\n\n        [Fact]\n        public async Task Returns_Null_For_Null_Body()\n        {\n            var nullBodyResponseTemplate = new ResponseTemplate { Body = null };\n\n            var response = await _strategy.GetResponseBodyBytesFromTemplate(nullBodyResponseTemplate);\n\n            response.Should()\n                .BeNull();\n        }\n\n        [Fact]\n        public async Task Returns_Response_When_Body_Is_Set()\n        {\n            var bodyOnlyResponseTemplate = new ResponseTemplate { Body = \"randomdata\" };\n\n            var bodyBytes = Encoding.UTF8.GetBytes(bodyOnlyResponseTemplate.Body.ToString());\n\n            var response = await _strategy.GetResponseBodyBytesFromTemplate(bodyOnlyResponseTemplate);\n\n            response.Should()\n                .BeEquivalentTo(bodyBytes);\n        }\n    }\n}"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Response/DefaultResponseBodyStrategyTest.cs",
    "content": "﻿using FluentAssertions;\nusing Xunit;\n\nnamespace Mockaco.Tests.Templating\n{\n    public class DefaultResponseBodyStrategyTest\n    {\n        private readonly DefaultResponseBodyStrategy _strategy;\n        private readonly ResponseTemplate _defaulResponseTemplate;\n        private readonly ResponseTemplate _responseTemplateWithContentType;\n\n        public DefaultResponseBodyStrategyTest()\n        {\n            _strategy = new DefaultResponseBodyStrategy();\n\n            _defaulResponseTemplate = new ResponseTemplate();\n\n            _responseTemplateWithContentType = new ResponseTemplate();\n            _responseTemplateWithContentType.Headers.Add(HttpHeaders.ContentType, HttpContentTypes.ApplicationJson);\n        }\n\n        [Fact]\n        public void Can_Handle_Response_Template_With_Default_Properties()\n        {\n            _strategy.CanHandle(_defaulResponseTemplate)\n                .Should()\n                .BeTrue();\n        }\n\n        [Fact]\n        public void Can_Handle_Response_Template_With_Content_Type()\n        {\n            _strategy.CanHandle(_responseTemplateWithContentType)\n                .Should()\n                .BeTrue();\n        }\n\n        [Fact]\n        public void Returns_Response_For_Any_Response_Template_By_Default()\n        {\n            var response = _strategy.GetResponseBodyStringFromTemplate(_defaulResponseTemplate);\n\n            response.Should()\n                .BeNull();\n        }\n\n        [Fact]\n        public void Returns_Null_For_Null_Body()\n        {\n            var nullBodyResponseTemplate = new ResponseTemplate { Body = null };\n\n            var response = _strategy.GetResponseBodyStringFromTemplate(nullBodyResponseTemplate);\n\n            response.Should()\n                .BeNull();\n        }\n    }\n}"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Response/JsonResponseBodyStrategyTest.cs",
    "content": "﻿using FluentAssertions;\nusing Newtonsoft.Json.Linq;\nusing Xunit;\nusing System;\n\nnamespace Mockaco.Tests.Templating\n{\n    public class JsonResponseBodyStrategyTest\n    {\n        private static string UnindentedValidJson = \"{\\\"property1\\\":\\\"property1Value\\\"}\";\n        private static string IndentedValidJson = \"{\"\n                        + Environment.NewLine + \"  \\\"property1\\\": \\\"property1Value\\\"\"\n                        + Environment.NewLine + \"}\";\n\n        private readonly JsonResponseBodyStrategy _strategy;\n        private readonly ResponseTemplate _validJsonResponseTemplate;\n\n        public JsonResponseBodyStrategyTest()\n        {\n            _strategy = new JsonResponseBodyStrategy();\n\n            _validJsonResponseTemplate = new ResponseTemplate { Body = JToken.Parse(UnindentedValidJson) };\n        }\n\n        [Fact]\n        public void Can_Handle_Valid_Json_Response_Body_By_Default()\n        {\n            _strategy.CanHandle(_validJsonResponseTemplate)\n                .Should()\n                .BeTrue();\n        }\n\n        [Fact]\n        public void Can_Handle_Valid_Json_Response_Body_With_Application_Json_Content_Type_Header()\n        {\n            _validJsonResponseTemplate.Headers.Add(HttpHeaders.ContentType, HttpContentTypes.ApplicationJson);\n\n            _strategy.CanHandle(_validJsonResponseTemplate)\n                .Should()\n                .BeTrue();\n        }\n\n        [Fact]\n        public void Can_Not_Handle_Valid_Json_Response_Body_With_Others_Content_Type_Header()\n        {\n            _validJsonResponseTemplate.Headers.Add(HttpHeaders.ContentType, \"any/content-type\");\n\n            _strategy.CanHandle(_validJsonResponseTemplate)\n                .Should()\n                .BeFalse();\n        }\n\n        [Fact]\n        public void Returns_Response_With_Not_Indented_Valid_Json()\n        {\n            _validJsonResponseTemplate.Indented = false;\n\n            var response = _strategy.GetResponseBodyStringFromTemplate(_validJsonResponseTemplate);\n\n            response.Should()\n                .Be(UnindentedValidJson);\n        }\n\n        [Fact]\n        public void Returns_Response_With_Indented_Valid_Json()\n        {\n            _validJsonResponseTemplate.Indented = true;\n\n            var response = _strategy.GetResponseBodyStringFromTemplate(_validJsonResponseTemplate);\n\n            response.Should()\n                .Be(IndentedValidJson);\n        }\n\n        [Fact]\n        public void Returns_Response_With_Indented_Valid_Json_By_Default()\n        {\n            var response = _strategy.GetResponseBodyStringFromTemplate(_validJsonResponseTemplate);\n\n            response.Should()\n                .Be(IndentedValidJson);\n        }\n\n        [Fact]\n        public void Returns_Null_For_Null_Body()\n        {\n            var nullBodyResponseTemplate = new ResponseTemplate { Body = null };\n\n            var response = _strategy.GetResponseBodyStringFromTemplate(nullBodyResponseTemplate);\n\n            response.Should()\n                .BeNull();\n        }\n    }\n}"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Response/ResponseBodyFactoryTest.cs",
    "content": "﻿using FluentAssertions;\nusing Moq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Mockaco.Tests.Templating.Response\n{\n    public class ResponseBodyFactoryTest\n    {\n        [Fact]\n        public async Task Can_Handle_Null_Returned_From_Response_Body_Strategy()\n        {\n            var responseBodyStrategy = Moq.Mock.Of<IResponseBodyStrategy>(\n                s => s.CanHandle(It.IsAny<ResponseTemplate>()) && s.GetResponseBodyBytesFromTemplate(It.IsAny<ResponseTemplate>()) == Task.FromResult<byte[]>(null));\n\n            var factory = new ResponseBodyFactory(new[] { responseBodyStrategy });\n\n            var responseTemplate = new ResponseTemplate { Body = null };\n\n            var bodyBytes = await factory.GetResponseBodyBytesFromTemplate(responseTemplate);\n\n            bodyBytes.Should()\n                .BeNull();\n        }\n    }\n}"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Response/XmlResponseBodyStrategyTest.cs",
    "content": "﻿using FluentAssertions;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing Xunit;\n\nnamespace Mockaco.Tests.Templating\n{\n    public class XmlResponseBodyStrategyTest\n    {\n        private static string UnindentedValidXml = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><root><hung bat=\\\"saw\\\">-820689514</hung><clay among=\\\"roof\\\"><wet>lunch</wet><yard either=\\\"event\\\"><product><!--green dry rose baby classroom thick-->174824199.0168128</product><![CDATA[express work bottle]]><exchange>-1202804739.2211328</exchange></yard></clay></root>\";\n        private static string IndentedValidXml = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\"\n                        + Environment.NewLine + \"<root>\"\n                        + Environment.NewLine + \"  <hung bat=\\\"saw\\\">-820689514</hung>\"\n                        + Environment.NewLine + \"  <clay among=\\\"roof\\\">\"\n                        + Environment.NewLine + \"    <wet>lunch</wet>\"\n                        + Environment.NewLine + \"    <yard either=\\\"event\\\">\"\n                        + Environment.NewLine + \"      <product>\"\n                        + Environment.NewLine + \"        <!--green dry rose baby classroom thick-->174824199.0168128</product><![CDATA[express work bottle]]><exchange>-1202804739.2211328</exchange></yard>\"\n                        + Environment.NewLine + \"  </clay>\"\n                        + Environment.NewLine + \"</root>\";\n\n        private XmlResponseBodyStrategy _strategy;\n\n        public XmlResponseBodyStrategyTest()\n        {\n            _strategy = new XmlResponseBodyStrategy();\n        }\n\n        [Fact]\n        public void Can_Not_Handle_Response_Template_With_Default_Properties()\n        {\n            var responseTemplate = new ResponseTemplate();\n\n            _strategy.CanHandle(responseTemplate)\n                .Should().BeFalse();\n        }\n\n        [Fact]\n        public void Can_Not_Handle_Response_Template_With_Other_Content_Type()\n        {\n            var responseTemplate = new ResponseTemplate();\n            responseTemplate.Headers.Add(HttpHeaders.ContentType, \"any/content-type\");\n\n            _strategy.CanHandle(responseTemplate)\n                .Should().BeFalse();\n        }\n\n        [Fact]\n        public void Can_Handle_Response_Template_With_Application_Xml_Content_Type()\n        {\n            var responseTemplate = new ResponseTemplate();\n            responseTemplate.Headers.Add(HttpHeaders.ContentType, HttpContentTypes.ApplicationXml);\n\n            _strategy.CanHandle(responseTemplate)\n                .Should().BeTrue();\n        }\n\n        [Fact]\n        public void Can_Handle_Response_Template_With_Text_Xml_Content_Type()\n        {\n            var responseTemplate = new ResponseTemplate();\n            responseTemplate.Headers.Add(HttpHeaders.ContentType, HttpContentTypes.TextXml);\n\n            _strategy.CanHandle(responseTemplate)\n                .Should().BeTrue();\n        }\n\n        [Fact]\n        public void Returns_Response_With_Not_Indented_Valid_Xml()\n        {\n            var responseTemplate = new ResponseTemplate();\n            responseTemplate.Headers.Add(HttpHeaders.ContentType, HttpContentTypes.ApplicationXml);\n            responseTemplate.Body = JToken.FromObject(IndentedValidXml);\n            responseTemplate.Indented = false;\n\n            var response = _strategy.GetResponseBodyStringFromTemplate(responseTemplate);\n\n            response\n                .Should().Be(UnindentedValidXml);\n        }\n\n        [Fact]\n        public void Returns_Response_With_Indented_Valid_Xml()\n        {\n            var responseTemplate = new ResponseTemplate();\n            responseTemplate.Headers.Add(HttpHeaders.ContentType, HttpContentTypes.ApplicationXml);\n            responseTemplate.Body = JToken.FromObject(UnindentedValidXml);\n            responseTemplate.Indented = true;\n\n            var response = _strategy.GetResponseBodyStringFromTemplate(responseTemplate);\n\n            response\n                .Should().Be(IndentedValidXml);\n        }\n\n        [Fact]\n        public void Returns_Response_With_Indented_Valid_Xml_By_Default()\n        {\n            var responseTemplate = new ResponseTemplate();\n            responseTemplate.Headers.Add(HttpHeaders.ContentType, HttpContentTypes.ApplicationXml);\n            responseTemplate.Body = JToken.FromObject(UnindentedValidXml);\n\n            var response = _strategy.GetResponseBodyStringFromTemplate(responseTemplate);\n\n            response\n                .Should().Be(IndentedValidXml);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Scripting/LocalizedFakerFactoryTest.cs",
    "content": "﻿using FluentAssertions;\nusing Microsoft.Extensions.Logging;\nusing System.Linq;\nusing Xunit;\n\nnamespace Mockaco.Tests.Scripting\n{\n    public class LocalizedFakerFactoryTest\n    {\n        private LocalizedFakerFactory _localizedFakerFactory;\n\n        public LocalizedFakerFactoryTest()\n        {\n            _localizedFakerFactory = new LocalizedFakerFactory(Moq.Mock.Of<ILogger<LocalizedFakerFactory>>());\n        }\n\n        [Fact]\n        public void Gets_Localized_Faker_Based_On_Http_Accept_Language_Header()\n        {            \n            var faker = _localizedFakerFactory.GetFaker(new[] { \"pt-BR\" });\n\n            faker.Locale.Should().Be(\"pt_BR\");\n        }\n\n        [Fact]\n        public void Gets_Default_Faker_When_No_Accept_Language_Header_Is_Present()\n        { \n            var faker = _localizedFakerFactory.GetFaker(Enumerable.Empty<string>());\n\n            faker.Locale.Should().Be(\"en\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Scripting/ScriptRunnerFactoryTest.cs",
    "content": "﻿using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace Mockaco.Tests.Templating.Scripting\n{\n    public class ScriptRunnerFactoryTest\n    {\n        [Theory]\n        [InlineData(@\"JsonConvert.SerializeObject(new DateTime(2012, 04, 23, 18, 25, 43, 511, DateTimeKind.Utc))\", @\"\\\"\"2012-04-23T18:25:43\\.511Z\\\"\"\")]\n        [InlineData(@\"new PhoneNumbers().BrazilianPhoneNumber()\", @\"[0-9]+\")]\n        [InlineData(@\"new Faker().Random.Guid().ToString()\", @\"[a-z0-9\\-]+\")]\n        [InlineData(@\"Regex.IsMatch(\"\"abc\"\", \"\".*\"\").ToString()\", @\"True\")]\n        [InlineData(@\"new[] {1, 2, 3, 4, 5, 6, 7}.Count().ToString()\", @\"7\")]\n        public async Task Can_Run_Scripts_From_Builtin_Namespaces(string input, string regexPattern)\n        {\n            var mockLogger = Moq.Mock.Of<ILogger<ScriptRunnerFactory>>();\n            var mockOptions = Moq.Mock.Of<IOptionsMonitor<MockacoOptions>>(o => o.CurrentValue == new MockacoOptions());\n\n            var runner = new ScriptRunnerFactory(mockLogger, mockOptions);\n            var result = await runner.Invoke<string, string>(\"\", input);\n\n            Assert.Matches(regexPattern, result);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/TemplateTransformerTest.cs",
    "content": "﻿using FluentAssertions;\nusing Microsoft.Extensions.Logging;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Mockaco.Tests.Templating\n{\n    public class TemplateTransformerTest\n    {\n        [Theory]\n        [TextFileData(\"Templating/Transforms_Plain_Json_Template.json\")]\n        public async Task Transforms_Plain_Json_Template(string content)\n        {\n            var templateTransformer = new TemplateTransformer(Moq.Mock.Of<IScriptRunnerFactory>(), Moq.Mock.Of<ILogger<TemplateTransformer>>());\n\n            var rawTemplate = Moq.Mock.Of<IRawTemplate>(t => t.Content == content);\n            var scriptContext = Moq.Mock.Of<IScriptContext>();\n            Moq.Mock.Get(scriptContext).Setup(m => m.Global).Returns(Moq.Mock.Of<IGlobalVariableStorage>());\n            \n            var transformedTemplate = await templateTransformer.TransformAndSetVariables(rawTemplate, scriptContext);\n\n            Assert(transformedTemplate);\n        }\n\n        [Theory]\n        [TextFileData(\"Templating/Transforms_Scripted_Json_Template.json\")]\n        public async Task Transforms_Scripted_Json_Template(string content)\n        {\n            var rawTemplate = Moq.Mock.Of<IRawTemplate>(t => t.Content == content);\n            var scriptContext = Moq.Mock.Of<IScriptContext>();\n            Moq.Mock.Get(scriptContext).Setup(m => m.Global).Returns(Moq.Mock.Of<IGlobalVariableStorage>());\n\n            var scriptRunnerFactory = Moq.Mock.Of<IScriptRunnerFactory>(f =>\n            f.Invoke<IScriptContext, object>(scriptContext, \"Request.Route[\\\"parameter1\\\"] == \\\"firstParameter\\\"\") == Task.FromResult((object)true)\n            && f.Invoke<IScriptContext, object>(scriptContext, \"Faker.Random.Number(1,7)\") == Task.FromResult((object)5)\n            && f.Invoke<IScriptContext, object>(scriptContext, \"JsonConvert.SerializeObject(new DateTime(2012, 04, 23, 18, 25, 43, 511, DateTimeKind.Utc))\") == Task.FromResult((object)\"\\\"2012-04-23T18:25:43.511Z\\\"\"));\n\n            var templateTransformer = new TemplateTransformer(scriptRunnerFactory, Moq.Mock.Of<ILogger<TemplateTransformer>>());\n\n            var transformedTemplate = await templateTransformer.TransformAndSetVariables(rawTemplate, scriptContext);\n\n            Assert(transformedTemplate);\n        }\n\n        private static void Assert(Template transformedTemplate)\n        {\n            transformedTemplate.Request.Method.Should()\n                .Be(\"POST\");\n\n            transformedTemplate.Request.Route.Should()\n                .Be(\"this/is/the/{parameter1}/route/{parameter2}\");\n\n            transformedTemplate.Request.Condition.Should()\n                .BeTrue();\n\n            transformedTemplate.Response.Delay.Should()\n                .HaveValue(\"Response.Delay is set\");\n\n            transformedTemplate.Response.Indented.Should()\n                .HaveValue(\"Response.Indented is set\");\n\n            transformedTemplate.Response.Status.Should()\n                .Be(HttpStatusCode.Created);\n\n            transformedTemplate.Response.Headers.Should()\n                .HaveCount(2);\n\n            transformedTemplate.Response.Body[\"id\"]?.ToString().Should()\n                .Be(\"1\");\n\n            transformedTemplate.Response.Body[\"message\"]?.ToString().Should()\n                .Be(\"Hello world\");\n\n            transformedTemplate.Response.Body[\"createdAt\"]?.Type.Should()\n               .Be(JTokenType.Date);\n\n            transformedTemplate.Response.Body[\"createdAt\"]?.Value<DateTime>().Should()\n               .Be(new DateTime(2012, 04, 23, 18, 25, 43, 511, DateTimeKind.Utc));\n\n            transformedTemplate.Callback.Method.Should()\n                .Be(\"PUT\");\n\n            transformedTemplate.Callback.Url.Should()\n                .Be(\"http://callback-address/route/to/call\");\n\n            transformedTemplate.Callback.Delay.Should()\n                .HaveValue(\"Callback.Delay is set\");\n\n            transformedTemplate.Callback.Timeout.Should()\n                .HaveValue(\"Callback.Timeout is set\");\n\n            transformedTemplate.Callback.Indented.Should()\n                .HaveValue(\"Callback.Indented is set\");\n\n            transformedTemplate.Callback.Headers.Should()\n                .HaveCount(2);\n\n            transformedTemplate.Callback.Body[\"key\"]?.ToString().Should()\n               .Be(\"2\");\n\n            transformedTemplate.Callback.Body[\"key\"]?.Type.Should()\n               .Be(JTokenType.Integer);\n\n            transformedTemplate.Callback.Body[\"topic\"]?.ToString().Should()\n                .Be(\"Hello callback\");\n\n            transformedTemplate.Callback.Body[\"updatedAt\"]?.Type.Should()\n               .Be(JTokenType.Date);\n\n            transformedTemplate.Callback.Body[\"updatedAt\"]?.Value<DateTime>().Should()\n               .Be(new DateTime(2003, 02, 01, 19, 00, 00, DateTimeKind.Utc));\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Transforms_Plain_Json_Template.json",
    "content": "{\n  \"request\": {\n    \"method\": \"POST\",\n    \"route\": \"this/is/the/{parameter1}/route/{parameter2}\",\n    \"condition\": true\n  },\n  \"response\": {\n    \"delay\": 1000,\n    \"indented\": true,\n    \"status\": \"201\",\n    \"headers\": {\n      \"X-Header-1\": \"1\",\n      \"X-Header-2\": \"2\"\n    },\n    \"body\": {\n      \"id\": \"1\",\n      \"message\": \"Hello world\",\n      \"createdAt\": \"2012-04-23T18:25:43.511Z\"\n    }\n  },\n  \"callback\": {\n    \"method\": \"PUT\",\n    \"url\": \"http://callback-address/route/to/call\",\n    \"delay\": 2000,\n    \"timeout\": 10000,\n    \"indented\": false,\n    \"headers\": {\n      \"Callback-Header-Foo\": \"Foo\",\n      \"Callback-Header-Bar\": \"Bar\"\n    },\n    \"body\": {\n      \"key\": 2,\n      \"topic\": \"Hello callback\",\n      \"updatedAt\": \"2003-02-01T19:00:00.000Z\"\n    }\n  }\n}"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Templating/Transforms_Scripted_Json_Template.json",
    "content": "{\n  \"request\": {\n    \"method\": \"POST\",\n    \"route\": \"this/is/the/{parameter1}/route/{parameter2}\",\n    \"condition\": \"<#=Request.Route[\"parameter1\"] == \"firstParameter\"#>\"\n  },\n  \"response\": {\n    \"delay\": \"<#=Faker.Random.Number(1,7)#>\",\n    \"indented\": true,\n    \"status\": \"201\",\n    \"headers\": {\n      \"X-Header-1\": \"1\",\n      \"X-Header-2\": \"2\"\n    },\n    \"body\": {\n      \"id\": \"1\",\n      \"message\": \"Hello world\",\n      \"createdAt\": <#=JsonConvert.SerializeObject(new DateTime(2012, 04, 23, 18, 25, 43, 511, DateTimeKind.Utc))#>\n    }\n  },\n  \"callback\": {\n    \"method\": \"PUT\",\n    \"url\": \"http://callback-address/route/to/call\",\n    \"delay\": 2000,\n    \"timeout\": 10000,\n    \"indented\": false,\n    \"headers\": {\n      \"Callback-Header-Foo\": \"Foo\",\n      \"Callback-Header-Bar\": \"Bar\"\n    },\n    \"body\": {\n      \"key\": 2,\n      \"topic\": \"Hello callback\",\n      \"updatedAt\": \"2003-02-01T19:00:00.000Z\"\n    }\n  }\n}"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/TextFileDataAttribute.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Reflection;\nusing Xunit.Sdk;\n\nnamespace Mockaco.Tests\n{\n    public class TextFileDataAttribute : DataAttribute\n    {\n        private readonly string _filePath;\n\n        public TextFileDataAttribute(string filePath)\n        {\n            _filePath = filePath;\n        }\n\n        public override IEnumerable<object[]> GetData(MethodInfo testMethod)\n        {\n            if (testMethod == null) { throw new ArgumentNullException(nameof(testMethod)); }\n\n            var path = Path.IsPathRooted(_filePath)\n                ? _filePath\n                : Path.GetRelativePath(Directory.GetCurrentDirectory(), _filePath);\n\n            if (!File.Exists(path))\n            {\n                throw new ArgumentException($\"Could not find file at path: {path} (current directory is {Directory.GetCurrentDirectory()})\");\n            }\n\n            var fileData = File.ReadAllText(_filePath);\n\n            yield return new object[] { fileData };\n        }\n    }\n}\n"
  },
  {
    "path": "test/Mockaco.AspNetCore.Tests/Usings.cs",
    "content": "global using Xunit;"
  },
  {
    "path": "test/_postman/Mockaco.postman_collection.json",
    "content": "{\n\t\"info\": {\n\t\t\"_postman_id\": \"53119370-0818-4475-9413-cd931b81d1f5\",\n\t\t\"name\": \"Mockaco\",\n\t\t\"schema\": \"https://schema.getpostman.com/json/collection/v2.1.0/collection.json\"\n\t},\n\t\"item\": [\n\t\t{\n\t\t\t\"name\": \"Hello\",\n\t\t\t\"event\": [\n\t\t\t\t{\n\t\t\t\t\t\"listen\": \"test\",\n\t\t\t\t\t\"script\": {\n\t\t\t\t\t\t\"exec\": [\n\t\t\t\t\t\t\t\"pm.test(\\\"Status code is 200\\\", function () {\\r\",\n\t\t\t\t\t\t\t\"    pm.response.to.have.status(200);\\r\",\n\t\t\t\t\t\t\t\"});\"\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"type\": \"text/javascript\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"request\": {\n\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\"header\": [],\n\t\t\t\t\"url\": {\n\t\t\t\t\t\"raw\": \"http://host.docker.internal:5000/hello/fulano\",\n\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\"host\",\n\t\t\t\t\t\t\"docker\",\n\t\t\t\t\t\t\"internal\"\n\t\t\t\t\t],\n\t\t\t\t\t\"port\": \"5000\",\n\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\"hello\",\n\t\t\t\t\t\t\"fulano\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"response\": []\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Verify hello\",\n\t\t\t\"event\": [\n\t\t\t\t{\n\t\t\t\t\t\"listen\": \"test\",\n\t\t\t\t\t\"script\": {\n\t\t\t\t\t\t\"exec\": [\n\t\t\t\t\t\t\t\"pm.test(\\\"Status code is 200\\\", function () {\\r\",\n\t\t\t\t\t\t\t\"    pm.response.to.have.status(200);\\r\",\n\t\t\t\t\t\t\t\"});\"\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"type\": \"text/javascript\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"request\": {\n\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\"header\": [],\n\t\t\t\t\"url\": {\n\t\t\t\t\t\"raw\": \"http://host.docker.internal:5000/_mockaco/verification?route=/hello/fulano\",\n\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\"host\",\n\t\t\t\t\t\t\"docker\",\n\t\t\t\t\t\t\"internal\"\n\t\t\t\t\t],\n\t\t\t\t\t\"port\": \"5000\",\n\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\"_mockaco\",\n\t\t\t\t\t\t\"verification\"\n\t\t\t\t\t],\n\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"key\": \"route\",\n\t\t\t\t\t\t\t\"value\": \"/hello/fulano\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"response\": []\n\t\t}\n\t]\n}"
  },
  {
    "path": "website/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "website/README.md",
    "content": "# Website\n\nThis website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.\n\n### Installation\n\n```\n$ yarn\n```\n\n### Local Development\n\n```\n$ yarn start\n```\n\nThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.\n\n### Build\n\n```\n$ yarn build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n\n### Deployment\n\nUsing SSH:\n\n```\n$ USE_SSH=true yarn deploy\n```\n\nNot using SSH:\n\n```\n$ GIT_USER=<Your GitHub username> yarn deploy\n```\n\nIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.\n"
  },
  {
    "path": "website/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "website/blog/authors.yml",
    "content": "natenho:\n  name: Renato Lima\n  title: Maintainer of Mockaco\n  url: https://github.com/natenho\n  image_url: https://github.com/natenho.png"
  },
  {
    "path": "website/docs/chaos/index.md",
    "content": "# Chaos Engineering\n\nEnabling chaos engineering, behavior different from what is expected will be randomly inserted into the calls, such as errors and delays, with this it is possible to verify how the client behaves in unforeseen situations.\n\n## How to enable Chaos Engineering\n\nTo enable chaos it is necessary to set the 'Enabled' variable to 'true' as shown in the example below (see [Configuration](../configuration/index.md) for more details):\n\n```\n\"Mockaco\": {\n    ...\n    \"Chaos\": {\n        \"Enabled\": true,\n    },\n    ...\n  },\n```\n\nin `appsettings.json`.\n\n## Types of answers with chaos\n\n- Behavior: Return HTTP Error 503 (Service Unavailable)\n- Exception: Return HTTP Error 500 (Internal Server Erro)\n- Latency: Randomly add delay time to a call\n- Result: Return HTTP Error 400 (Bad Request)\n- Timeout: Waits a while and returns error 408 (Request Timeout)\n\n## How to define parameters\n\nParameters are defined inside the Chaos key\n\n```\n\"Mockaco\": {\n    ...\n    \"Chaos\": {\n        \"Enabled\": true,\n        \"ChaosRate\": 20,\n        \"MinimumLatencyTime\": 500,\n        \"MaximumLatencyTime\": 3000,\n        \"TimeBeforeTimeout\": 10000\n    },\n    ...\n  },\n```\n\nin `appsettings.json`.\n\n| Parameter          | Description                                                        | Default |\n| ------------------ | ------------------------------------------------------------------ | ------- |\n| Enabled            | Option to enable and disable chaos (true / false)                  | false   |\n| ChaosRate          | Percentage of calls affected by chaos (0 - 100)                    | 20      |\n| MinimumLatencyTime | Minimum latency in milliseconds when the latency strategy is drawn | 500     |\n| MaximumLatencyTime | Maximum latency in milliseconds when the latency strategy is drawn | 3000    |\n| TimeBeforeTimeout  | Time in milliseconds before timeout error                          | 10000   |\n"
  },
  {
    "path": "website/docs/configuration/_category_.json",
    "content": "{\n  \"label\": \"Configuration\",\n  \"position\": 7\n}\n"
  },
  {
    "path": "website/docs/configuration/index.md",
    "content": "# Configuration\n\n### App Settings\n\nThe configuration for Mockaco can be easily customized using the appsettings*.json files located within the Settings folder. These files allow you to configure various options [provided by ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration).\n\nHere are the different appsettings*.json files and their purposes:\n\n- *appsettings.Production.json*: Use this file to customize Mockaco when running it as an executable or dotnet tool.\n- *appsettings.Docker.json*: This file is specifically used to customize Mockaco when running in a Docker container.\n- *appsettings.Development.json*: When running Mockaco in debug mode, such as inside Visual Studio, you can use this file to customize its behavior. This environment is typically set through the launchSettings.json file.\n\nThese appsettings*.json files provide a convenient way to adjust Mockaco's settings based on the specific environment in which it is running.\n\nTo customize Mockaco, locate the appropriate appsettings*.json file based on your deployment scenario and modify the configuration options according to your requirements.\n\nFor instance you could override the default URLs Mockaco will listen to, just by changing the configuration like this:\n\n```json\n{\n  \"Urls\": \"http://+:8080;https://+:8443\"\n}\n```\n\n### Environment variables\n\nYou can also use **environment variables** to override the configuration. For example, you can set the `ASPNETCORE_URLS` environment variable to `http://+:8080;https://+:8443` to achieve the same result as the appsettings.json example.\n\nAnother way to set the configuration is through command line arguments.\n\n### Command line\n\nTo pass mockaco specific options through **command line**, you can use the `--Mockaco` prefix. For example, to set the `DefaultHttpStatusCode` to `NotFound` you can use the following command:\n\n```bash\ndotnet mockaco run --Mockaco:DefaultHttpStatusCode=NotFound\n```\n\nPlease refer to the [ASP.NET Core documentation](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration) for more information on how to customize the configuration.\n\nMockaco specific options are listed in the next topics.\n\n## Mockaco\n\n```json\n{\n    \"Mockaco\": {\n        \"DefaultHttpStatusCode\": \"OK\",\n        \"ErrorHttpStatusCode\": \"NotImplemented\",\n        \"DefaultHttpContentType\": \"application/json\",\n        \"References\": [],\n        \"Imports\": [],\n        \"MatchedRoutesCacheDuration\": 60,\n        \"MockacoEndpoint\": \"_mockaco\",\n        \"VerificationEndpointName\": \"verification\"\n    }\n}\n```\n\n### `DefaultHttpStatusCode`\n\nSet the default HTTP status code returned when the mock does not specify one.\n\nDefault: `OK` (200)\n\n### `ErrorHttpStatusCode`\n\nSet the default HTTP status code in case there is no matching mock available.\n\nDefault: `NotImplemented` (501)\n\n### `DefaultHttpContentType`\n\nSet the default HTTP `Content-Type` header response when the mock does not specify one.\n\nDefault: `application/json`\n\n### `References`\n\nA list of additional references to other .NET assemblies to extend scripting engine.\n\nDefault: `[]`\n\n### `Imports`\n\nA list of additional namespaces to be imported and made available in scripting engine. It is the same as calling `using` in C#.\n\nDefault: `[]`\n\n### `MatchedRoutesCacheDuration`\n\nSet the cache duration in minutes to be used by the verification endpoint.\n\nDefault: `60`\n\n### `MockacoEndpoint`\n\nThe exclusive endpoint to access internal features.\n\nDefault: `_mockaco`\n\n### `VerificationEndpointName`\n\nThe name of the verification endpoint.\n\nDefault: `verification`\n\n### `TemplateFileProvider`\n\nConfigure the mock template file provider.\n\n#### `Path`\n\nDefine the mock template files path.\n\nDefault: `Mocks`\n\n## `Serilog`\n\nConfigure [Serilog logger](https://github.com/serilog/serilog-settings-configuration)\n\nJust as Mockaco options, to pass Serilog specific options through command line, you can use the `--Serilog` prefix. For example, to set the `MinimumLevel` to `Information` you can use the following command:\n\n```bash\ndotnet mockaco run --Serilog:MinimumLevel=Information\n```"
  },
  {
    "path": "website/docs/generator/_category_.json",
    "content": "{\n  \"label\": \"Generator\",\n  \"position\": 6\n}\n"
  },
  {
    "path": "website/docs/generator/index.md",
    "content": "# Generator\n\nThis feature allows to generate mock templates based on provided specification eg. OpenApi, simply using `generate` command.\n\nUsage:\n\n```\nmockaco generate [url/path to the specification] --provider=[provider name]\n```\n\nExample:\n\n```\nmockaco generate https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json --provider=openapi\n```\n\nThe above command will generate mocks based on Petstore OpenAPI specification example.\n\n## Supported specifications\n- [OpenApi](https://spec.openapis.org/oas/latest.html)"
  },
  {
    "path": "website/docs/guides/_category_.json",
    "content": "{\n  \"label\": \"Guides\",\n  \"position\": 100,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"description\": \"5 minutes to learn the most important Docusaurus concepts.\"\n  }\n}\n"
  },
  {
    "path": "website/docs/guides/mocking-raw.md",
    "content": "# Mocking binary/raw responses\n\nMockaco is able to respond raw file contents, so it's possible to return a file, image or any static file content.\n\n## Example 1 - Image\n\nThis example returns a static image file.\n\nCreate a file named `image.json` under `Mocks` folder. Copy any JPG image file named ```image01.jpg``` into the directory.\n\n```json\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"/images/image01.jpg\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"image/jpeg\"\n    },\n    \"file\": \"Mocks/image01.jpg\"\n  }\n}\n```\n\nThe `Content-Type` header must be set to the appropriate MIME type.\n\t\n### Testing\n\nThe best way to test this example is to open your favorite browser and access the URL http://localhost:5000/images/image01.jpg.\n\n## Example 2 - Binary File Download\n\nThis example instructs browsers to download any binary file.\n\nCreate a file named `binary.json` under `Mocks` folder. Copy any file named ```binary.dat``` into the directory.\n\n```json\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"/binary.dat\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"application/octet-stream\",\n      \"Content-Disposition\": \"attachment; filename=\\\"binary-example.dat\\\"\"\n    },\n    \"file\": \"Mocks/binary.dat\"\n  }\n}\n```\n\nThe ```Content-Disposition``` header is responsible to instruct the browser to download the file instead of guessing how to render it.\n\n### Testing\n\nThe best way to test this example is to open your favorite browser and access the URL http://localhost:5000/binary.dat.\n\nIt will start downloading a file with the default name ```binary-example.dat``` as specified in ```filename=``` field in ```Content-Disposition``` header.\n\n## Example 3 - Raw XML file\n\nThis example simply shows how to mock a static raw XML response so it can be sent \"as-is\", without any parsing.\n\n Create a XML file named ```mock.xml``` under `Mocks` folder.\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<root>\n    <theSongName>Glycerine</theSongName>\n    <theAlbum year=\"1994\">Sixteen Stone</theAlbum>\n</root>\n```\n\nCreate a file named `rawxml.json` under `Mocks` folder.\n```json\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"/raw-xml-example\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"application/xml\"      \n    },\n    \"file\": \"Mocks/mock.xml\"\n  }\n}\n```\n\n### Send the request and get the mocked response\n\n```console\n$ curl -iX GET http://localhost:5000/raw-xml-example\n```\n```http\nHTTP/1.1 200 OK\nDate: Tue, 13 Aug 2019 05:09:40 GMT\nContent-Type: application/xml\nServer: Kestrel\nTransfer-Encoding: chunked\n\n<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<root>\n    <theSongName>Glycerine</theSongName>\n    <theAlbum year=\"1994\">Sixteen Stone</theAlbum>\n</root>\n```"
  },
  {
    "path": "website/docs/guides/mocking-stateful.md",
    "content": "# Stateful mocks\n\nMockaco can persist states to allow mocking multiple behaviors for the same endpoint.\nThese states are simple global variables persisted in memory and available for all active mocks.\n\nTo create a global variable, simply use the `Global` object indexer and set it inside a code block, surrounded by `<#` and `#>`):\n\n```\n<#\n\tGlobal[\"my-custom-variable\"] = \"my-custom-state\";\n#>\n```\n\nTo retrieve an existing global variable:\n\n```\n<#=Global[\"my-custom-variable\"]#>\n```\n\nGlobal object can hold any object such as boolean flags, strings or your entire request payload, for instance.\n\nInexistent global variables will always return `null`.\n\n## Example\n\nLet's suppose the following scenario of 3 requests, registering a customer:\n\n1. GET /customers returns HTTP 404 Not Found\n2. POST /customers returns HTTP 201 Created\n3. GET /customers returns HTTP 200 OK with the newly created customer (at this moment, the mock should reset its state so the behavior can be repeated)\n\n## Create the request/response templates\n\nCreate `customers-get-not-found.json` under the Mocks folder:\n\n```\n{\n  \"request\": {\n\t\"method\": \"GET\",\n\t\"route\": \"/customers\",\n\t\"condition\": \"<#=Global[\"get-customers-state\"] == null#>\"\n  },\n  \"response\": {\n\t\"status\": \"NotFound\"\t\n  }\n}\n```\n\nThis template will match GET /customers requests whenever the global variable `get-customers-state` is `null`\n\nThen, create `customers-post.json` under the Mocks folder:\n\n```\n{ \n  \"request\": {\n\t\"method\": \"POST\",\n\t\"route\": \"/customers\"\n  },\n  \"response\": {\n\t\"status\": \"201\"\t\n  }\n}\n<#\n\t// Set the state with the request payload\n\tGlobal[\"get-customers-state\"] = Request.Body;\n#>\n```\n\nThis template will match POST requests to the same endpoint. It will store the entire request body into a global variable named `get-customers-state` and return HTTP 201 Created.\n\nLast, create `customers-get-ok.json` under the Mocks folder:\n\n```\n{\n  \"request\": {\n\t\"method\": \"GET\",\n\t\"route\": \"/customers\",\n\t\"condition\": \"<#=Global[\"get-customers-state\"] != null#>\"\n  },\n  \"response\": {\n\t\"status\": \"200\",\n\t\"body\": <#=Global[\"get-customers-state\"].ToString()#>\n  }\n}\n<#\n\t// Reset state after the request\n\tGlobal[\"get-customers-state\"] = null;\n#>\n```\n\nThis template will match GET /customers requests whenever the global variable `get-customers-state` is *not* `null`.\nIt will return HTTP 200 OK and output the content of the global variable named `get-customers-state` in the response body.\nAfter that, it resets the global variable named `get-customers-state` back to `null`, allowing the cycle to be restarted.\n\n## Testing the Example\n\n```console\ncurl -iX GET http://localhost:5000/customers\n```\n```http\nHTTP/1.1 404 Not Found\nDate: Tue, 21 Jul 2020 05:56:25 GMT\nContent-Type: application/json\nServer: Kestrel\nContent-Length: 0\n```\n\n```console\ncurl -iX POST \\\n  --url http://localhost:5000/customers \\\n  --header 'Content-Type: application/json' \\\n  --data $'{ \"name\": \"John Doe\" }'\n```\n```http\nHTTP/1.1 201 Created\nDate: Tue, 21 Jul 2020 05:58:39 GMT\nContent-Type: application/json\nServer: Kestrel\nContent-Length: 0\n```\n\n```console\ncurl -iX GET http://localhost:5000/customers\n```\n```http\nHTTP/1.1 200 OK\nDate: Tue, 21 Jul 2020 06:06:05 GMT\nContent-Type: application/json\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\n  \"name\": \"John Doe\"\n}\n```\n\n```console\ncurl -iX GET http://localhost:5000/customers\n```\n```http\nHTTP/1.1 404 Not Found\nDate: Tue, 21 Jul 2020 05:56:25 GMT\nContent-Type: application/json\nServer: Kestrel\nContent-Length: 0\n```"
  },
  {
    "path": "website/docs/guides/mocking-xml.md",
    "content": "# Mocking XML responses\n\nMockaco is able to parse XML request and make its elements available to be used in the response and/or callback templates.\n\n## Example\n\nThis example is composed by a XML request which is transformed and returned with a different schema.\n\nGiven the XML request payload:\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<root>\n    <theSongName>Glycerine</theSongName>\n    <theAlbum year=\"1994\">Sixteen Stone</theAlbum>\n</root>\n```\n\n## Create the request/response template\nCreate a file named `songs.json` under `Mocks` folder:\n\n```\n{\n  \"request\": {\n    \"method\": \"POST\",\n    \"route\": \"songs\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"application/xml\"\n    },\n    \"body\": \"\n<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" ?>\n<song>\n  <name><#=Request.Body[\"root\"]?[\"theSongName\"]#></name>\n  <album>\n    <name><#=Request.Body[\"root\"]?[\"theAlbum\"]?[\"#text\"]#></name>\n    <year><#=Request.Body[\"root\"]?[\"theAlbum\"]?[\"@year\"]#></year>\n  </album>\n</song>\n\"\n  }\n}\n```\n\nThe `Content-Type` header must be set to `application/xml` or `text/xml`.\nNotice that XML double quotes must be properly escaped, but inline C# scripts should not be escaped.\n\nTo access the request XML data and use it inside the response:\n- An element **without** attributes can be directly accessed by its name:\n```csharp\nRequest.Body[\"root\"]?[\"theSongName\"]\n```\n- An element **with** one or more attributes can be accessed using `#text` key:\n```csharp\nRequest.Body[\"root\"]?[\"theAlbum\"]?[\"#text\"]\n```\n- An element attribute can be accessed using `@` prefix:\n```csharp\nRequest.Body[\"root\"]?[\"theAlbum\"]?[\"@year\"]\n```\n\t\n## Send the request and get the mocked response\n```console\ncurl -iX POST \\\n  --url http://localhost:5000/songs \\\n  --header 'Content-Type: application/xml' \\\n  --data $'<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\\r\\n<root>\\r\\n\t<theSongName>Glycerine</theSongName>\\r\\n\t<theAlbum year=\"1994\">Sixteen Stone</theAlbum>\\r\\n</root>'\n```\n```http\nHTTP/1.1 200 OK\nDate: Tue, 13 Aug 2019 05:09:40 GMT\nContent-Type: application/xml\nServer: Kestrel\nTransfer-Encoding: chunked\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<song>\n  <name>Glycerine</name>\n  <album>\n    <name>Sixteen Stone</name>\n    <year>1994</year>\n  </album>\n</song>\n```\n"
  },
  {
    "path": "website/docs/health-checks/_category_.json",
    "content": "{\n  \"label\": \"Health Checks\",\n  \"position\": 8\n}\n"
  },
  {
    "path": "website/docs/health-checks/index.md",
    "content": "# Health Checks\n\nHealth checks are often useful when Mockaco container is being used.\n\n## `/_mockaco/health`\n\nTo determine if Mockaco is running and listening, you can check its health status by accessing http://localhost:5000/_mockaco/health. A successful request will receive an HTTP 200 OK response.\n\n```\n$ curl -i http://localhost:5000/_mockaco/health\nHTTP/1.1 200 OK\nContent-Type: text/plain\nDate: Sun, 11 Jun 2023 17:46:30 GMT\nServer: Kestrel\nCache-Control: no-store, no-cache\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\nPragma: no-cache\nTransfer-Encoding: chunked\n\nHealthy\n```\n\n## `/_mockaco/ready`\n\nDuring the startup process, Mockaco asynchronously loads and caches mocks. The duration of this process may vary depending on the number of mocks being loaded. However, it's important to note that while this loading is taking place, some requests may not be served as expected, resulting in an HTTP 501 response.\n\nTo avoid this potential race condition, it is recommended to utilize the readiness endpoint.\n\nWhile the mocks are still loading, the service will respond with an HTTP 503 status code. Here's an example of the response you would receive:\n\n```\n$ curl -i http://localhost:5000/_mockaco/ready\nHTTP/1.1 503 Service Unavailable\nContent-Type: text/plain\nDate: Sun, 11 Jun 2023 17:47:55 GMT\nServer: Kestrel\nCache-Control: no-store, no-cache\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\nPragma: no-cache\nTransfer-Encoding: chunked\n\nUnhealthy\n```\n\nOnce the startup process is complete and Mockaco is ready to handle requests, the readiness endpoint will return an HTTP 200 OK status code. Here's an example:\n\n```\n$ curl -i http://localhost:5000/_mockaco/ready\nHTTP/1.1 200 OK\nContent-Type: text/plain\nDate: Sun, 11 Jun 2023 17:50:59 GMT\nServer: Kestrel\nCache-Control: no-store, no-cache\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\nPragma: no-cache\nTransfer-Encoding: chunked\n\nHealthy\n```\n\n### Using readiness endpoint in Dockerfile\n\nBy default, Mockaco containers does not expose health checks. However, you can create a derived Docker image and utilize the `HEALTHCHECK` instruction to ensure the container's health status is determined only after all the mocks have been loaded. Here's an example Dockerfile:\n\n```Dockerfile\nFROM natenho/mockaco\nCOPY Mocks /app/Mocks\nHEALTHCHECK --interval=5s --timeout=3s \\\n    CMD curl --fail http://localhost:5000/_mockaco/ready || exit 1\n```\n\nIn this Dockerfile, the `Mocks` folder is copied into the `/app/Mocks` directory within the container. You can replace Mocks with the actual path of your local Mocks folder.\n\nThe `HEALTHCHECK` instruction sets up a health check for the container. It specifies the interval and timeout for checking the health, and it runs the curl command to verify the readiness endpoint `http://localhost:5000/_mockaco/ready`. If the curl command fails (returns a non-zero exit status), the container will be considered unhealthy and exit with status code 1.\n\nTo build the derived Docker image, use the following command:\n\n```shell\ndocker build -t mockaco-image .\n```\n\nReplace mockaco-image with your desired image name.\n\nOnce the image is built, you can run a container based on it, mapping the container's port 5000 to the host's port of your choice (e.g., 8080):\n\n```shell\ndocker run -d -p 8080:5000 --name mockaco-container mockaco-image\n```\n\nNow the container will be running with the Mocks folder mapped to `/app/Mocks` inside it, and the health check will be performed periodically using the specified curl command."
  },
  {
    "path": "website/docs/quick-start/_category_.json",
    "content": "{\n  \"label\": \"Quick Start\",\n  \"position\": 2,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"description\": \"Mockaco is an HTTP-based API mock server with fast setup.\"\n  }\n}\n"
  },
  {
    "path": "website/docs/quick-start/create-mock.md",
    "content": "---\nsidebar_position: 2\n---\n\n# Create a mock\n\nCreate a file named `ping-pong.json` under `Mocks` folder.\n\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\",\n\t\"route\": \"ping\"\n  },\n  \"response\": {\n\t\"status\": \"OK\",\n\t\"body\": {\n\t  \"response\": \"pong\"\n\t}\n  }\n}\n```\n\nThis example contains a request/response template, meaning \"Whenever you receive a ```GET``` request in the route ```/ping```, respond with status ```OK``` and the body ```{ \"response\": \"pong\" }```\""
  },
  {
    "path": "website/docs/quick-start/install-run.md",
    "content": "---\nsidebar_position: 1\n---\n\n# Install and run\n\nChoose your favorite way to install Mockaco locally or in your server.\n\n## .NET CLI\n\nInstall and run as a dotnet tool:\n\n```console\n$ dotnet tool install -g mockaco\n$ mockaco --urls \"http://localhost:5000\"\n```\n\nA random local port is chosen if `--urls` parameter is not provided.\n\n## Docker\n\nYou can run Mockaco from the official [Docker image](https://hub.docker.com/r/natenho/mockaco) (replace ```/your/folder``` with an existing directory of your preference):\n\n```console\n$ docker run --pull always -it --rm -p 5000:5000 -v /your/folder:/app/Mocks natenho/mockaco\n```\n\n### Docker command breakdown\nFlag | Description | Purpose |\n:--- | :--- | :--- |\n`docker run` | The foundational command | Creates and starts a new Docker container. |\n`--pull always` | Always pull image | Ensures you're running the latest version from the registry. |\n`-it` | Interactive TTY | Attaches your terminal to the container to see logs and use `Ctrl+C`. |\n`--rm` | Remove on exit | Automatically cleans up and deletes the container when it stops. |\n`-p 5000:5000` | Publish port | Maps `localhost:5000` on your machine to port `5000` in the container. The port exposed by the container is 5000 (HTTP) by default. |\n`-v /your/folder:/app/Mocks` | Mount volume | Links your local folder to the container so `mockaco` can read your mock files. |\n`natenho/mockaco` | The Docker image | The actual application being run—the mock server itself. |\n\n## From sources\n\nOr your can run it directly from sources:\n\n```console\n$ git clone https://github.com/natenho/Mockaco.git\n$ cd Mockaco\\src\\Mockaco\n$ dotnet run\n```\n\nA random local port is chosen if `--urls` parameter is not provided.\n"
  },
  {
    "path": "website/docs/quick-start/test-mock.md",
    "content": "# Test\n\nSend a request and get the mocked response.\nAccess [http://localhost:5000/ping](http://localhost:5000/ping) or call the API via curl:\n\n```\ncurl -iX GET http://localhost:5000/ping\n\nHTTP/1.1 200 OK\nDate: Wed, 13 Mar 2019 00:22:49 GMT\nContent-Type: application/json\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\n\t\"response\": \"pong\"\n}\n```"
  },
  {
    "path": "website/docs/reference-scripting/_category_.json",
    "content": "{\n  \"label\": \"Scripting Reference\",\n  \"position\": 3\n}\n"
  },
  {
    "path": "website/docs/reference-scripting/faker.md",
    "content": "# Faker\n\n## Basic usage\n\nA `Faker` facade object is available to generate fake data within a script.\n\n```\n{\n  \"request\": {\n    \"method\": \"GET\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"body\": {\n      \"name\": \"<#= Faker.Name.FullName() #>\",\n      \"company\": \"<#= Faker.Company.CompanyName() #>\",\n      \"city\": \"<#= Faker.Address.City() #>\"\n    }\n  }\n}\n```\n\n```shell\n$ curl http://localhost:5000\n{\n  \"name\": \"Mollie Beahan\",\n  \"company\": \"Ziemann, Anderson and Durgan\",\n  \"city\": \"Ritchiemouth\"\n}\n```\n\n##  Generating a list of items\n\nThis example creates a list of 10 items:\n\n```\n{\n    \"request\": {\n        \"method\": \"GET\",\n        \"route\": \"/names\"\n    },\n    \"response\": {\n        \"body\": <#=\nclass Person\n{\n    public int ID { get; set; }\n    public string Name { get; set; }\n}\n\nvar count =  10;\nvar people = new Person[count];\n\nfor(var i = 0; i < count; i++ ) {\n    people[i] = new Person { ID = i + 1, Name = new Faker().Person.FullName };\n}\n\nreturn JsonConvert.SerializeObject(people);\n#>\n    }\n}\n```\n\n## Localization\n\nTo generate localized data, use the `Accept-Language` HTTP header when sending a request to Mockaco. Defaults to `en` (english) fake data.\n\n```\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {\n\t\"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n\t\"body\": {\n\t  \"name\": \"<#= Faker.FullName() #>\",\n\t  \"company\": \"<#= Faker.Company.CompanyName() #>\",\n      \"city\": \"<#= Faker.Address.City() #>\"\n\t}\n  }\n}\n```\n\n```shell\n$ curl -X GET \"http://localhost:5000\" -H \"Accept-Language: ru\"\n{\n  \"name\": \"Екатерина Мельникова\",\n  \"company\": \"Гусев - Никонов\",\n  \"city\": \"Тула\"\n}\n```\n\n```shell\n$ curl -X GET \"http://localhost:5000\" -H \"Accept-Language: pt-BR\"\n{\n  \"name\": \"Maitê Albuquerque\",\n  \"company\": \"Costa S.A.\",\n  \"city\": \"Santo André\"\n}\n```\n\n## Using Bogus extensions\n\nTo use [Bogus API Extension Methods](https://github.com/bchavez/Bogus?tab=readme-ov-file#api-extension-methods), consider the following example, using the `Bogus.Extensions.Brazil` namespace to generate brazilian CPF numbers:\n\n```\n{\n  \"request\": {\n    \"method\": \"GET\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"body\": <#= Faker.Person.Cpf() #>\n  }\n}\n```\n\nUse the [Imports option](/docs/configuration/#imports) to import the Bogus extension methods on Mockaco startup:\n\n```shell\n$ mockaco --urls=http://+:5000 --Mockaco:Imports:0=\"Bogus.Extensions.Brazil\"\n```\n\nThen call the mock endpoint:\n\n```shell\n$ curl -i \"http://localhost:5000\"\nHTTP/1.1 200 OK\nContent-Type: application/json\nDate: Sun, 10 Mar 2024 23:44:50 GMT\nServer: Kestrel\nTransfer-Encoding: chunked\n\n\"422.244.459-62\"\n```\n"
  },
  {
    "path": "website/docs/reference-scripting/global.md",
    "content": "# Global\n\nThe Global object is a global variable that can be used to store variables that are shared between all mock requests. Its underlying storage is a `Dictionary<string, object>` object, meaning that you can store any type of variable in it. The state is not persisted between server restarts.\n\n## Store a variable along a mock request\n\n```\n<#\n    Global[\"my-custom-variable\"] = \"hello\";\n#>\n{\n  \"request\": {\n\t\"method\": \"GET\",\n\t\"route\": \"ping\"\n  },\n  \"response\": {\n\t\"status\": \"OK\",\n\t\"body\": {\n\t  \"response\": \"<#=Global[\"my-custom-variable\"] #>\"\n\t}\n  }\n}\n```\n\n```shell\n$ curl http://localhost:5000/ping\n{\n  \"response\": \"hello\"\n}\n```\n\n## Store state between mock calls\n\nThe Global object is shared between all mock requests, meaning that you can store a variable in one mock and use it in another.\n\n```\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"store\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"body\": {\n      \"response\": \"This request stores a variable\"\n    }\n  }\n  <#\n    Global[\"my-custom-variable\"] = \"hello!\";\n  #>\n}\n```\n\n```\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"retrieve\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"body\": {\n      \"response\": \"The variable is <#=Global[\"my-custom-variable\"] #>\"\n    }\n  }\n}\n```\n\n```shell\n$ curl http://localhost:5000/store\n{\n  \"response\": \"This request stores a variable\"\n}\n\n$ curl http://localhost:5000/retrieve\n{\n  \"response\": \"The variable is hello!\"\n}\n```\n\nThis feature can be used to simulate stateful APIs behaviors. Refer to the [Stateful mocks guide](/docs/guides/mocking-stateful) for more information."
  },
  {
    "path": "website/docs/reference-scripting/index.md",
    "content": "# Scripting\n\nEvery part of the mock file is scriptable, so you can add code to programmatically generate parts of the template.\n\nUse C# code surrounded by `<#=` and `#>`.\n\n:::caution Escaping\n\nA convenient feature of Mockaco is that you don't need to escape the code inside the JSON.\nAlthough it pays off, in the other hand, the invalid JSON file may be a little hard to indent.\n\n:::\n\nThe mock code and generation will run for each request.\n\nThe scripts are compiled and executed via [Roslyn](https://github.com/dotnet/roslyn/wiki/Scripting-API-Samples).\n\n### Example\n\n```json\n{\n  \"request\": {\n    \"method\": \"GET\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"body\": {\n      \"currentYear\": \"<#= DateTime.Now.Year #>\"\n    }\n  }\n}\n```\n\nThe code tag structure resembles [T4 Text Template Engine](https://github.com/mono/t4). In fact, this project leverages parts of T4 engine code to parse mock templates.\n\nFor multi-line code, you need to use `return` at the end of the code block:\n\n```\n<#=\n  var count = 10\n  var people = new int[count];\n\n  for(var i = 0; i < count; i++ ) {\n      people[i] = i + 1;\n  }\n\n  return JsonConvert.SerializeObject(people);\n#>\n```\n\n## Generating fake data\n\nThere is a `Faker` object available to generate fake data.\n\n```\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {\n\t  \"status\": \"OK\",\n\t  \"body\": {\n      \"id\": \"<#= Faker.Random.Guid() #>\",\n      \"number\": \"<#= Faker.Random.Number(1, 1000) #>\",\n      \"fruit\": \"<#= Faker.PickRandom(new[] { \"apple\", \"banana\", \"orange\", \"strawberry\", \"kiwi\" }) #>\",\n      \"recentDate\": <#= JsonConvert.SerializeObject(Faker.Date.Recent()) #>\n\t  }\n  }\n}\n```\n\nThe built-in fake data is generated via [Bogus](https://github.com/bchavez/Bogus). You can use any documented method from Bogus library.\nThe faker can also generate localized data using `Accept-Language` HTTP header. Defaults to `en` (english) fake data.\n\n## Accessing request data\n\nIt's possible to access request data within the response template.\nThere is a `Request` object available to access request data.\n\n```\n{\n  \"request\": {\n\t  \"method\": \"PUT\",\n\t  \"route\": \"customers/{id}\"\n  },\n  \"response\": {\n\t  \"status\": \"OK\",\n\t  \"body\": {\n      \"url\": \"<#= Request.Url #>\",\n      \"customerId\": \"<#= Request.Route[\"id\"] #>\",\n      \"acceptHeader\": \"<#= Request.Header[\"Content-Type\"] #>\",\n      \"queryString\": \"<#= Request.Query[\"dummy\"] #>\",\n      \"requestBodyAttribute\": \"<#= Request.Body[\"address\"]?[0] #>\"\n    }\n  }\n}\n```\n\n## Accessing response data\n\nIn the same way, response data can be used within the callback request template.\nThere is a `Response` object available to access the generated response data.\n\n```\n{\n  \"request\": {\n    \"method\": \"PUT\",\n    \"route\": \"customers/{id}\"\n  },\n  \"response\": {\n    \"delay\": \"<#=Faker.Random.Number(1,7)#>\",\n    \"indented\": true,\n    \"status\": \"201\",\n    \"headers\": {\n      \"X-Header-1\": \"1\",\n      \"X-Header-2\": \"2\"\n    },\n    \"body\": {\n      \"id\": \"1\",\n      \"message\": \"Hello world\",\n\t  \"generatedRandomNumber\": <#=Faker.Random.Number(1,10000)#>\n    }\n  },\n  \"callback\": {\n    \"method\": \"POST\",\n    \"url\": \"https://postman-echo.com/post\",\n    \"timeout\": 1000,\n    \"headers\": {\n      \"Callback-Header-Message\": \"<#=Response.Body[\"message\"]#>\"\n    },\n    \"body\": {\n      \"responseRandomNumber\": \"The mocked response was <#= Response.Body[\"generatedRandomNumber\"] #>\"\n    }\n  }\n}\n```\n"
  },
  {
    "path": "website/docs/reference-scripting/request.md",
    "content": "# Request\n\nThe Request object has the following properties:\n\n## Url\n\nAn instance of [`Uri`](https://learn.microsoft.com/dotnet/api/system.uri) class containing request URL data.\n\n## Route\n\nA [`IReadOnlyDictionary<string, string>`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlydictionary-2) containing route parameters. Missing keys will return an empty string. To check the existence of a key, use the `ContainsKey` method.\n\n## Header\n\nA [`IReadOnlyDictionary<string, string>`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlydictionary-2) containing request headers. Missing keys will return an empty string. To check the existence of a key, use the `ContainsKey` method.\n\n## Query\n\nA [`IReadOnlyDictionary<string, string>`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlydictionary-2) containing query parameters. Missing keys will return an empty string. To check the existence of a key, use the `ContainsKey` method.\n\n## Body\n\nA [`JToken`](https://www.newtonsoft.com/json/help/html/t_newtonsoft_json_linq_jtoken.htm) object containing request body data. The content of the request body is parsed as JSON and returned as a `JToken` object. The content types that Mockaco can parse are `application/json`, `application/xml`, `text/xml`, `text/plain`, `application/x-www-form-urlencoded` and `multipart/form-data`.\n\n### Querying the body as a dictionary\n\nThe body can be queried like a dictionary of dictionaries. A simple `Request.Body[\"key\"]?[\"subKey\"]` will return the value of the required `subKey`. In the same way, `Request.Body[0]` would return the first item\n\nIf the key is not found, it will return `null`, so it is a good practice to use the [null conditional operator `?`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-).\n\n```\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"songs/{id}\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"body\": {\n        \"id\": \"<#=Request.Route[\"id\"] #>\",\n        \"name\": \"<#=Request.Body[\"songs\"]?[0]?[\"name\"] #>\",\n        \"album\": {\n            \"name\": \"<#=Request.Body[\"songs\"]?[0]?[\"album\"]?[\"name\"] #>\",\n            \"year\": \"<#=Request.Body[\"songs\"]?[0]?[\"album\"]?[\"year\"] #>\"\n        }\n    }\n  }\n}\n```\n\n### Querying the body using JSONPath\n\nYou can also use the [`SelectToken`](https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JToken_SelectToken.htm) and [`SelectTokens`](https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JToken_SelectTokens.htm) methods to query the body using JSONPath, which is a convenient way to traverse and filter fields from a complex object. These methods returns one or more `JToken` objects containing the selected tokens. If the token is not found, it returns `null`.\n\nGiven the following mock template:\n\n```\n{\n  \"request\": {\n    \"method\": \"POST\",\n    \"route\": \"/json_path\"\n  },\n  \"response\": {\n    \"body\": {\n      \"Manufacturer\": \"<#= Request.Body.SelectToken(\"Manufacturers[0].Name\") #>\",\n      \"Price\": \"<#= Request.Body.SelectToken(\"Manufacturers[0].Products[0].Price\") #>\",\n      \"ProductName\": \"<#= Request.Body.SelectToken(\"Manufacturers[1].Products[0].Name\") #>\",\n      \"AcmeManufacturer\": <#= Request.Body.SelectToken(\"$.Manufacturers[?(@.Name == 'Acme Co')]\") #>,\n      \"FilteredProducts\": <#= JsonConvert.SerializeObject(Request.Body.SelectTokens(\"$..Products[?(@.Price >= 50)].Name\")) #>\n    }\n  }\n}\n```\n\n```shell\n$ curl -X POST 'http://localhost:5000/json_path' \\\n-H 'Content-Type: application/json' \\\n-d '\n{\n  \"Stores\": [\n    \"Lambton Quay\",\n    \"Willis Street\"\n  ],\n  \"Manufacturers\": [\n    {\n      \"Name\": \"Acme Co\",\n      \"Products\": [\n        {\n          \"Name\": \"Anvil\",\n          \"Price\": 50\n        }\n      ]\n    },\n    {\n      \"Name\": \"Contoso\",\n      \"Products\": [\n        {\n          \"Name\": \"Elbow Grease\",\n          \"Price\": 99.95\n        },\n        {\n          \"Name\": \"Headlight Fluid\",\n          \"Price\": 4\n        }\n      ]\n    }\n  ]\n}'\n\n{\n  \"Manufacturer\": \"Acme Co\",\n  \"Price\": \"50\",\n  \"ProductName\": \"Elbow Grease\",\n  \"AcmeManufacturer\": {\n    \"Name\": \"Acme Co\",\n    \"Products\": [\n      {\n        \"Name\": \"Anvil\",\n        \"Price\": 50\n      }\n    ]\n  },\n  \"FilteredProducts\": [\n    \"Anvil\",\n    \"Elbow Grease\"\n  ]\n}\n```\n\nSee also:\n\n- [Querying JSON with SelectToken](https://www.newtonsoft.com/json/help/html/SelectToken.htms)\n- [Querying JSON with LINQ](https://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm)\n"
  },
  {
    "path": "website/docs/reference-scripting/response.md",
    "content": "# Response\n\nThe Response object is accessible **after** the mock is generated. This object contains response that was sent to the client. It has the following properties:\n\n## Header\n\nA [`IReadOnlyDictionary<string, string>`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlydictionary-2) containing response headers. Missing keys will return an empty string. To check the existence of a key, use the `ContainsKey` method.\n\n## Body\n\nA [`JToken`](https://www.newtonsoft.com/json/help/html/t_newtonsoft_json_linq_jtoken.htm) object containing response body data."
  },
  {
    "path": "website/docs/reference-template/_category_.json",
    "content": "{\n  \"label\": \"Mock Template Reference\",\n  \"position\": 3,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"description\": \"JSON mock template reference\"\n  }\n}\n"
  },
  {
    "path": "website/docs/reference-template/callback/_category_.json",
    "content": "{\n  \"label\": \"callback object\",\n  \"position\": 3,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"description\": \"Prepare the mock to call another API whenever a request arrives.\"\n  }\n}\n"
  },
  {
    "path": "website/docs/reference-template/callback/body-attribute.md",
    "content": "# body attribute\n\nSets the content to be sent to another server.\n\nIf omitted, empty or null, defaults to empty.\n\n## Example\n\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {\n\t\"status\": \"OK\",\n\t\"body\": {\n\t  \"currentTime\": \"<#= DateTime.Now.ToString() #>\"\n\t}\n  },\n  \"callback\": {\n\t\"method\": \"POST\",\n\t\"body\": {\n\t\t\"message\": \"The response was <#= Response.Body[\"currentTime\"]?.ToString() #>\"\n\t},\n\t\"url\": \"https://postman-echo.com/post\",\n  }\n}\n```\n\n:::tip Scripting tip\n\nThe request data and the generated response data can be accessed in callback to produce dynamic callback content.\n\n:::"
  },
  {
    "path": "website/docs/reference-template/callback/delay-attribute.md",
    "content": "# delay attribute\n\nWaits for a specific amount of time in milliseconds before sending the callback.\nIf omitted, empty or null, defaults to 0.\n\nThis delay is useful to simulate web-hooks after processing asynchronous requests.\n\n# Example\n\nIn this example, Mockaco will wait 5 seconds after the mocked response to send the callback.\n\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {\n\t\"status\": \"OK\"\n  },\n  \"callback\": {\n\t\"method\": \"POST\",\n\t\"body\": {\n\t\t\"message\": \"This request will be sent after 5 seconds\"\n\t},\n\t\"url\": \"https://postman-echo.com/post\",\n\t\"delay\": 5000\n  }\n}\n```"
  },
  {
    "path": "website/docs/reference-template/callback/headers-attribute.md",
    "content": "# headers attribute\n\nAllow to set headers of the callback request.\n\n## Example\n\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {\n\t\"status\": \"OK\"\n  },\n  \"callback\": {\n\t\"method\": \"POST\",\n\t\"headers\": {\t\t\n\t\t\"X-Foo\": \"Bar\"\n\t},\n\t\"body\": {\n\t\t\"message\": \"This request has headers!\"\n\t}\n  }\n}\n```"
  },
  {
    "path": "website/docs/reference-template/callback/method-attribute.md",
    "content": "# method attribute\n\nDefine which [HTTP request method](https://developer.mozilla.org/docs/Web/HTTP/Methods) will be used to send the callback request.\n\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {\n\t\"status\": \"OK\",\n\t\"body\": {\n\t  \"currentTime\": \"<#= DateTime.Now.ToString() #>\"\n\t}\n  },\n  \"callback\": {\n\t\"method\": \"DELETE\",\n\t\"url\": \"https://postman-echo.com/delete\"\n  }\n}\n```"
  },
  {
    "path": "website/docs/reference-template/callback/timeout-attribute.md",
    "content": "# timeout attribute\n\nSpecify an amount of time in milliseconds to wait for the callback request response.\n\nDefault: `5000`\n\n## Example\n\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {\n\t\"status\": \"OK\"\n  },\n  \"callback\": {\n\t\"method\": \"POST\",\n\t\"timeout\": 2000,\n\t\"body\": {\n\t\t\"message\": \"This request will timeout if the server does not reply in 2 seconds\"\n\t},\n\t\"url\": \"https://postman-echo.com/post\"\n  }\n}\n```"
  },
  {
    "path": "website/docs/reference-template/callback/url-attribute.md",
    "content": "# url attribute\n\nSet the callback target absolute URL. This attribute is required.\n\n"
  },
  {
    "path": "website/docs/reference-template/request/_category_.json",
    "content": "{\n  \"label\": \"request object\",\n  \"position\": 1,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"description\": \"Use this object to provide the necessary information for the engine to decide which response will be returned. To generate a response, all request attributes must match.\"\n  }\n}\n"
  },
  {
    "path": "website/docs/reference-template/request/condition-attribute.md",
    "content": "---\nsidebar_position: 3\n---\n# condition attribute\n\nAny condition that evaluates to ```true``` will return the response. The condition is suitable to be used with scripting.\n\nIf omitted, empty or null, defaults to ```true```.\n\n## Example\n```json\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"customers/{id}/accounts/{account_id}\",\n\t  \"condition\": \"<#= DateTime.Now.Second % 2 == 0 #>\"\n  },\n  \"response\": {\n    \"body\": \"Match!\"\n  }\n}\n```\n\nIn the example above, the mock will be returned for `GET customers/1234/accounts/123ABC`, leveraging `condition` [scripting](/docs/reference-scripting) to ensure that the mock matches only if the current time has an even second.\n\nThe condition can also be used to match based on query parameters:\n\n```json\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"any/{myVar}\",\n\t  \"condition\": \"<#= Request.Query[\"foo\"] == \"bar\" #>\"\n  },\n  \"response\": {\n    \"body\": \"Hello!\"\n  }\n}\n```\n\nThe mock will be returned for `GET any/xxx?foo=bar`"
  },
  {
    "path": "website/docs/reference-template/request/method-attribute.md",
    "content": "---\nsidebar_position: 1\n---\n# method attribute\n\nAny request with the matching HTTP method will return the response. Supported HTTP methods: GET, PUT, DELETE, POST, HEAD, TRACE, PATCH, CONNECT, OPTIONS.\nIf omitted, defaults to ```GET```.\n\n## Example\n```json\n{\n  \"request\": {\n\t  \"method\": \"GET\"\n  },\n  \"response\": {\n\t  \"status\": \"OK\"\n  }\n}\n```"
  },
  {
    "path": "website/docs/reference-template/request/route-attribute.md",
    "content": "---\nsidebar_position: 2\n---\n# route attribute\n\nAny request with the matching route will return the response. Any AspNet route template is supported.\n\nIf omitted, empty or null, defaults to base route (/).\n\n## Example\n```json\n{\n  \"request\": {\n\t  \"route\": \"customers/{id}/accounts/{account_id}\"\n  },\n  \"response\": {\n\t  \"status\": \"OK\"\n  }\n}\n```"
  },
  {
    "path": "website/docs/reference-template/response/_category_.json",
    "content": "{\n  \"label\": \"response object\",\n  \"position\": 2,\n  \"link\": {\n    \"type\": \"generated-index\",\n    \"description\": \"Compose the mocked response.\"\n  }\n}\n"
  },
  {
    "path": "website/docs/reference-template/response/body-attribute.md",
    "content": "# body attribute\n\nSets the HTTP response body.\n\nIf omitted, empty or null, defaults to empty.\n\nThe ```Content-Type``` header is used to process output formatting for certain MIME types. If omitted, defaults to ```application/json```.\n\n## Example\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {    \n\t\"status\": \"OK\",\n\t\"body\": {\n\t  \"foo\": \"Bar\"\n\t}\n  }\n}\n```\n\nSee also:\n\n - [Mocking binary/raw responses](/docs/guides/mocking-raw)\n - [Mocking XML responses](/docs/guides/mocking-raw)\n"
  },
  {
    "path": "website/docs/reference-template/response/delay-attribute.md",
    "content": "# delay attribute\n\nDefines a minimum response time in milliseconds. Useful to produce an artificial timeout.\n\nIf omitted, empty or null, defaults to ```0```.\n\n## Example\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {\n\t\"delay\": 4000,\n\t\"status\": \"OK\"\n  }\n}\n```"
  },
  {
    "path": "website/docs/reference-template/response/file-attribute.md",
    "content": "# file attribute\n\nAllow to define a file to be returned in body\n\n## Example\n\n```json\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"/images/image01.jpg\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"image/jpeg\"\n    },\n    \"file\": \"Mocks/image01.jpg\"\n  }\n}\n```\n\nSee also:\n\n - [Mocking binary/raw responses](/docs/guides/mocking-raw)\n - [Mocking XML responses](/docs/guides/mocking-raw)\n"
  },
  {
    "path": "website/docs/reference-template/response/headers-attribute.md",
    "content": "# headers attribute\n\nSets any HTTP response headers.\n\n## Example\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {    \n\t\"status\": \"OK\",\n\t\"headers\": {\n\t\t\"X-Foo\": \"Bar\"\n\t}\n  }\n}\n```"
  },
  {
    "path": "website/docs/reference-template/response/indented-attribute.md",
    "content": "# indented attribute\n\nSets the response body indentation for some structured content-types. If ommited, defaults to ```true```.\n\n## Example\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {    \n\t\"status\": \"OK\",\n\t\"body\": {\n\t  \"this\": \"json content\",\n\t  \"is\": \"supposed to be\",\n\t  \"in\": \"the same line\"\n\t},\n\t\"indented\": false\n  }\n}\n```\n\nResult:\n\n```\ncurl -iX GET http://localhost:5000\n\nHTTP/1.1 200 OK\nDate: Wed, 31 Jul 2019 02:57:30 GMT\nContent-Type: application/json\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\"this\":\"json content\",\"is\":\"supposed to be\",\"in\":\"the same line\"}\n```\n"
  },
  {
    "path": "website/docs/reference-template/response/status-attribute.md",
    "content": "# status attribute\n\nSets the HTTP status code for the response. Can be a text or numeric value, as defined in [System.Net.HttpStatusCode](https://docs.microsoft.com/en-us/dotnet/api/system.net.httpstatuscode) enumeration, so `NotFound` and `404` are both valid values for this field.\n\nIf omitted, empty or null, defaults to ```OK``` (`200`).\n\n## Example\n```json\n{\n  \"request\": {\n\t\"method\": \"GET\"\n  },\n  \"response\": {    \n\t\"status\": \"Forbidden\"\n  }\n}\n```"
  },
  {
    "path": "website/docs/request-matching/_category_.json",
    "content": "{\n  \"label\": \"Request Matching\",\n  \"position\": 2\n}\n"
  },
  {
    "path": "website/docs/request-matching/index.md",
    "content": "\n# Request Matching\n\nWhen a request is received, Mockaco follows a specific process:\n\nMockaco searches for files in alphabetical order.\n1. It compares the request against the criteria specified in the request object of each file.\n2. The first match that meets the criteria is selected. In case of ambiguity, Mockaco will prioritize mocks that have a condition.\n3. If no matching Mock file is found, Mockaco returns a default response of HTTP 501 (Not Implemented). Additionally, it provides a list of possible file parsing errors.\n\nThis process ensures that Mockaco handles incoming requests and provides appropriate responses based on the available mock files. In case of any errors, the default response serves as a helpful indicator for troubleshooting.\n\n## Criteria\n\nThe request matching is based on the [`request object`](/docs/category/request-object) defined in the mock template.\n\nPlease refer to [request object reference](/docs/category/request-object) for further details on how to use each criteria.\n\n### Matching HTTP method\n\nThe method is the HTTP verb used in the request. It is case-insensitive. If the method is not specified, Mockaco will match `GET` method.\n\nExample of a mock that matches a `POST` request:\n\n```\n{\n  \"request\": {\n    \"method\": \"POST\"\n  },\n  \"response\": {\n    \"status\": \"OK\"\n  }\n}\n```\n\n```shell\n$ curl -iX POST \"http://localhost:5000\"\nHTTP/1.1 200 OK\nContent-Length: 0\nContent-Type: application/json\nDate: Sun, 10 Mar 2024 23:10:33 GMT\nServer: Kestrel\n```\n\n### Matching request route\n\nThe route follows a similar pattern to the URL, but it contains the route parameters that can be later reused inside scripts.\n\nExample of a route with parameters that will match a request to `/customers/123`:\n\n```\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"customers/{id}\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"body\": {\n      \"name\": \"John Doe\"\n    }\n  }\n}\n```\n\n```shell\n$ curl -iX GET \"http://localhost:5000/customers/123\"\nHTTP/1.1 200 OK\nContent-Type: application/json\nDate: Sun, 10 Mar 2024 23:05:07 GMT\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\n  \"name\": \"John Doe\"\n}\n```\n\nThe route parameters are also accessible through scripting API and can be used inside the `condition` object to match the request, or event inside the response body:\n\n```\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"route\": \"customers/{id}\"\n    \"condition\": \"<#= Request.Route[\"id\"] == \"123\" #>\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"body\": {\n      \"customerId\": \"<#= Request.Route[\"id\"] #>\"\n    }\n  }\n}\n```\n\n```shell\n$ curl -iX GET \"http://localhost:5000/customers/123\"\nHTTP/1.1 200 OK\nContent-Type: application/json\nDate: Sun, 10 Mar 2024 23:06:35 GMT\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\n  \"customerId\": \"123\"\n}\n```\n\n### Matching query parameters\n\nQuery parameters are accessible through scripting API and can be used inside the `condition` object to match the request.\n\nThis example uses a condition to check if the query parameter `my-parameter` is equal to `good`. If the condition is met, the response body will contain a message.\n\n```\n{\n  \"request\": {\n\t\"method\": \"GET\",\n    \"condition\": \"<#= Request.Query[\"my-parameter\"] == \"good\" #>\"\n  },\n  \"response\": {\n\t\"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n\t\"body\": {\n\t  \"message\": \"Good query parameter\"\n\t}\n  }\n}\n```\n\n```shell\n$ curl -iX GET \"http://localhost:5000?my-parameter=good\"\nHTTP/1.1 200 OK\nContent-Type: application/json\nDate: Sun, 10 Mar 2024 23:02:31 GMT\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\n  \"message\": \"Good query parameter\"\n}\n```\n\nNotice that trying to get a missing query parameter will return an empty string. To check the existence of a query parameter, use the `ContainsKey` method.\n\n```\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"condition\": \"<#= Request.Query.ContainsKey(\"my-flag\") #>\"\n  },\n  \"response\": {\n    \"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"body\": {\n      \"message\": \"Query parameter exists\"\n    }\n  }\n}\n```\n\n```shell\n$ curl -iX GET \"http://localhost:5000?my-flag\"\nHTTP/1.1 200 OK\nContent-Type: application/json\nDate: Sun, 10 Mar 2024 23:00:37 GMT\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\n  \"message\": \"Query parameter exists\"\n}\n```\n\nThis another example uses Regex to check if the query parameter `word` contains only lowercase letters. If the condition is met, the word is returned in the response body.\n\n```\n{\n  \"request\": {\n\t\"method\": \"GET\",\n    \"condition\": \"<#= Regex.IsMatch(Request.Query[\"word\"], \"^[a-z]+$\") #>\"\n  },\n  \"response\": {\n\t\"status\": \"OK\",\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n\t\"body\": {\n\t  \"word\": \"<#= Request.Query[\"word\"] #>\"\n\t}\n  }\n}\n```\n\n```shell\n$ curl -iX GET \"http://localhost:5000?word=mockaco\"\nHTTP/1.1 200 OK\nContent-Type: application/json\nDate: Sun, 10 Mar 2024 22:56:40 GMT\nServer: Kestrel\nTransfer-Encoding: chunked\n\n{\n  \"word\": \"mockaco\"\n}\n```\n\n```shell\n$ curl -iX GET \"http://localhost:5000?word=Mockaco\"\nHTTP/1.1 501 Not Implemented\nContent-Type: application/json\nDate: Sun, 10 Mar 2024 22:56:23 GMT\nServer: Kestrel\nTransfer-Encoding: chunked\n\n[\n  {\n    \"Message\": \"Incoming request didn't match any mock\"\n  }\n]\n```"
  },
  {
    "path": "website/docs/verification/_category_.json",
    "content": "{\n  \"label\": \"Verification\",\n  \"position\": 5\n}\n"
  },
  {
    "path": "website/docs/verification/index.md",
    "content": "# Verification\n\nThere is a default endpoint provided that let you verify the last call for each mocked endpoint. The default path for this endpoint is ```http://localhost:5000/_mockaco/verification?route={path to verify}```.\n\n## Example: Verifying call to mocked endpoint\n\n### Verify request without body\n\nIf you have just called ```http://localhost:5000/hello/Jane Doe```, the verification endpoint\ncalled in the following way: ```http://localhost:5000/_mockaco/verification?route=/hello/Jane Doe``` will respond like so: \n```\n{\n    \"route\": \"/hello/Hello There\",\n    \"timestamp\": \"14:15\",\n    \"body\": \"\"\n}\n```\n\n### Verify request with body\n\nIf you have just called ```http://localhost:5000/hello/Jane Doe```, with the following body:\n```\n{\n    \"username\": \"Jane1\",\n    \"lastname\": \"Doe1\"\n}\n```\nthe verification endpoint called in the following way: ```http://localhost:5000/_mockaco/verification?route=/hello/Jane Doe``` will respond like so: \n```\n{\n    \"route\": \"/hello/Jane Doe\",\n    \"timestamp\": \"14:39\",\n    \"body\": \"{\\r\\n    \\\"username\\\": \\\"Jane1\\\",\\r\\n    \\\"lastname\\\": \\\"Doe1\\\"\\r\\n}\"\n}\n```\n\nBoth JSON body and x-www-form-urlencoded body are supported.\n\n### Verify request with headers\nIf you have just called ```http://localhost:5000/hello/Jane Doe```, with the following headers:\n```\n    x-user-id:someone@email.com\n    Authorization:some-bearer-token\n    endtoend:b9802abd-106f-4d50-b68e-de3198777456\n```\nthe verification endpoint called in the following way: ```http://localhost:5000/_mockaco/verification?route=/hello/Jane Doe``` will respond like so: \n```\n{\n    \"route\": \"/hello/Jane Doe\",\n    \"timestamp\": \"14:41\",\n    \"headers\": [\n        {\n            \"key\": \"x-user-id\",\n            \"value\": \"someone@email.com\"\n        },\n        {\n            \"key\": \"Authorization\",\n            \"value\": \"some-bearer-token\"\n        },\n        {\n            \"key\": \"endtoend\",\n            \"value\": \"b9802abd-106f-4d50-b68e-de3198777456\"\n        }\n    ],\n    \"body\": \"\"\n}\n```\n\n### Configure hidden headers in verification endpoint\nYou can configure to not display headers that are not relevant to your test. By default the following headers will not be displayed:  ```Accept, Connection, Host, User-Agent, Accept-Encoding, Postman-Token, Content-Type, Content-Length.```\n\n```\n\"Mockaco\": {\n    ...\n    \"VerificationIgnoredHeaders\": [        \n        \"Postman-Token\",\n        \"Some-Irrelevant-Header\",\n    ],\n    ...\n  },\n```\n\n\n## Configure custom name of verification endpoint\n\nYou can configure the default name of verification enpoint by modifying ```Mockaco.VerificationEndpointName``` and ```Mockaco.VerificationEndpointPrefix``` fields in ``appsettings.json`` file. So if you will rename it like so:\n\n```\n\"Mockaco\": {\n    ...\n    \"VerificationEndpointName\": \"customVerify\",\n    \"VerificationEndpointPrefix\": \"_internal\"\n  },\n```\n\nYou will be able to access the verification endpoint on ```http://localhost:5000/_internal/customVerify```\n\n## Configure the duration of cache storing last request for verification\n\nEach request with the exact time of being invoked, body and path is being stored in the internal .Net cache for 60 minutes. You can configure this time by changing\n\n```\n\"Mockaco\": {\n    ...\n    \"MatchedRoutesCacheDuration\": 60, \n    ...\n  },\n```\nin ```appsettings.json```.\n\n## Verification summary\n\nLet's assume that you have the following endpoints mocked:\n```\nhttp://localhost:5000/hello/{message}\nhttp://localhost:5000/test\n```\n\nWith the verification functionality you can check the last performed call for each of these 2 endpoints and different variations of {message}, so if you called these 2 endpoints in the following ways:\n\n```\ncurl --location --request GET 'http://localhost:5000/hello/Jane Doe'\ncurl --location --request GET 'http://localhost:5000/hello/Marzipan'\ncurl --location --request GET 'http://localhost:5000/hello/There!'\ncurl --location --request GET 'http://localhost:5000/test'\n```\n\nYou can perform these checks:\n\n```\nhttp://localhost:5000/_mockaco/verification?route=/hello/Jane Doe\nhttp://localhost:5000/_mockaco/verification?route=/hello/Marzipan\nhttp://localhost:5000/_mockaco/verification?route=/hello/There!\nhttp://localhost:5000/_mockaco/verification?route=/test\n```\nYou cannot perform verification based on the generic url like ```http://localhost:5000/_mockaco/verification?route=/hello/{message}```\n"
  },
  {
    "path": "website/docusaurus.config.js",
    "content": "// @ts-check\n// Note: type annotations allow type checking and IDEs autocompletion\n\nconst lightCodeTheme = require('prism-react-renderer/themes/github');\nconst darkCodeTheme = require('prism-react-renderer/themes/dracula');\n\n/** @type {import('@docusaurus/types').Config} */\nconst config = {\n  title: 'Mockaco',\n  tagline: 'Get your mock server up and running in no time!',\n  favicon: 'img/favicon.png',\n\n  // Set the production url of your site here\n  url: 'https://natenho.github.io/',\n  // Set the /<baseUrl>/ pathname under which your site is served\n  // For GitHub pages deployment, it is often '/<projectName>/'\n  baseUrl: '/Mockaco',\n\n  // GitHub pages deployment config.\n  // If you aren't using GitHub pages, you don't need these.\n  organizationName: 'natenho', // Usually your GitHub org/user name.\n  projectName: 'mockaco', // Usually your repo name.\n\n  onBrokenLinks: 'throw',\n  onBrokenMarkdownLinks: 'warn',\n\n  // Even if you don't use internalization, you can use this field to set useful\n  // metadata like html lang. For example, if your site is Chinese, you may want\n  // to replace \"en\" with \"zh-Hans\".\n  i18n: {\n    defaultLocale: 'en',\n    locales: ['en'],\n  },\n\n  presets: [\n    [\n      'classic',\n      /** @type {import('@docusaurus/preset-classic').Options} */\n      ({\n        docs: {\n          sidebarPath: require.resolve('./sidebars.js'),\n          // Please change this to your repo.\n          // Remove this to remove the \"edit this page\" links.\n          editUrl:\n            'https://github.com/natenho/Mockaco/tree/master/website',\n        },\n        // blog: {\n        //   showReadingTime: true,\n        //   // Please change this to your repo.\n        //   // Remove this to remove the \"edit this page\" links.\n        //   editUrl:\n        //     'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',\n        // },\n        theme: {\n          customCss: require.resolve('./src/css/custom.css'),\n        },\n      }),\n    ],\n  ],\n\n  themeConfig:\n    /** @type {import('@docusaurus/preset-classic').ThemeConfig} */\n    ({\n      // Replace with your project's social card\n      image: 'img/mockaco-social-card.png',\n      navbar: {\n        title: 'Mockaco',\n        logo: {\n          alt: 'Mockaco Logo',\n          src: 'img/logo.svg',\n        },\n        items: [\n          {\n            type: 'docSidebar',\n            sidebarId: 'tutorialSidebar',\n            position: 'left',\n            label: 'Docs',\n          },\n          {to: 'videos', label: 'Videos', position: 'left'},\n          {\n            href: 'https://github.com/natenho/mockaco',\n            position: 'right',\n            className: 'header-github-link header-icon-link',\n            'aria-label': 'GitHub repository',\n          },\n        ],\n      },\n      footer: {\n        style: 'dark',\n        links: [\n          {\n            title: 'Help',\n            items: [\n              {\n                label: 'Support',\n                href: 'https://github.com/natenho/Mockaco/issues',\n              },\n            ],\n          },\n        ],\n        copyright: `Copyright © ${new Date().getFullYear()} Renato Lima.`,\n      },\n      prism: {\n        theme: lightCodeTheme,\n        darkTheme: darkCodeTheme,\n      },\n      algolia: {\n        appId: 'XIH8B6F8KL',\n        apiKey: 'cc22bf63eb102dea42451bc77e907dae',\n        indexName: 'mockaco',\n        contextualSearch: true,\n        searchParameters: {},\n        searchPagePath: 'search',\n      },\n    }),\n};\n\nmodule.exports = config;\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"website\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"2.4.1\",\n    \"@docusaurus/preset-classic\": \"2.4.1\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"clsx\": \"^1.2.1\",\n    \"prism-react-renderer\": \"^1.3.5\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-player\": \"^2.12.0\",\n    \"yarn\": \"^1.22.19\"\n  },\n  \"devDependencies\": {\n    \"@docusaurus/module-type-aliases\": \"2.4.1\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"engines\": {\n    \"node\": \">=16.14\"\n  }\n}\n"
  },
  {
    "path": "website/sidebars.js",
    "content": "/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n\n The sidebars can be generated from the filesystem, or explicitly defined here.\n\n Create as many sidebars as you want.\n */\n\n// @ts-check\n\n/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */\nconst sidebars = {\n  // By default, Docusaurus generates a sidebar from the docs folder structure\n  tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],\n\n  // But you can create a sidebar manually\n  /*\n  tutorialSidebar: [\n    'intro',\n    'hello',\n    {\n      type: 'category',\n      label: 'Tutorial',\n      items: ['tutorial-basics/create-a-document'],\n    },\n  ],\n   */\n};\n\nmodule.exports = sidebars;\n"
  },
  {
    "path": "website/src/components/HomepageFeatures/index.js",
    "content": "import React from 'react';\nimport clsx from 'clsx';\nimport styles from './styles.module.css';\n\nconst FeatureList = [\n  {\n    title: 'Peel off the complexity',\n    Svg: require('@site/static/img/banana.svg').default,\n    description: (\n      <>\n        Simplify the setup and execution of API mocks, effortlessly\n      </>\n    ),\n  },\n  {\n    title: 'Pure C# scripting',\n    Svg: require('@site/static/img/c-sharp.svg').default,\n    description: (\n      <>\n        You don't need to learn a new specific language or API to add dynamic content to your mocks\n      </>\n    ),\n  },\n  {\n    title: 'Fake data generation',\n    Svg: require('@site/static/img/faker.svg').default,\n    description: (\n      <>\n        Experience the convenience of out-of-the-box built-in fake data generation\n      </>\n    ),\n  },\n];\n\nfunction Feature({Svg, title, description}) {\n  return (\n    <div className={clsx('col col--4')}>\n      <div className=\"text--center\">\n        <Svg className={styles.featureSvg} role=\"img\" />\n      </div>\n      <div className=\"text--center padding-horiz--md\">\n        <h3>{title}</h3>\n        <p>{description}</p>\n      </div>\n    </div>\n  );\n}\n\nexport default function HomepageFeatures() {\n  return (\n    <section className={styles.features}>\n      <div className=\"container\">\n        <div className=\"row\">\n          {FeatureList.map((props, idx) => (\n            <Feature key={idx} {...props} />\n          ))}\n        </div>\n      </div>\n    </section>\n  );\n}\n"
  },
  {
    "path": "website/src/components/HomepageFeatures/styles.module.css",
    "content": ".features {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n}\n\n.featureSvg {\n  height: 200px;\n  width: 200px;\n}\n\n"
  },
  {
    "path": "website/src/css/custom.css",
    "content": "/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n\n/* \n#0c6837 green\n#f7d417 yellow\n#08338f blue\n*/\n\n:root {\n  --ifm-color-primary: #0c6837;\n  --ifm-color-primary-dark: #0b5e32;\n  --ifm-color-primary-darker: #0a582f;\n  --ifm-color-primary-darkest: #084927;\n  --ifm-color-primary-light: #0d723d;\n  --ifm-color-primary-lighter: #0e783f;\n  --ifm-color-primary-lightest: #108748;\n  --ifm-code-font-size: 95%;\n  --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);\n  --ifm-background-color: #fcfcfc;\n}\n\n/* For readability concerns, you should choose a lighter palette in dark mode. */\n[data-theme='dark'] {\n  --ifm-color-primary: #25c2a0;\n  --ifm-color-primary-dark: #21af90;\n  --ifm-color-primary-darker: #1fa588;\n  --ifm-color-primary-darkest: #1a8870;\n  --ifm-color-primary-light: #29d5b0;\n  --ifm-color-primary-lighter: #32d8b4;\n  --ifm-color-primary-lightest: #4fddbf;\n  --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);\n}\n\n.header-icon-link {\n  padding: var(--ifm-navbar-item-padding-vertical) calc(var(--ifm-navbar-item-padding-horizontal) * 0.8);\n}\n\n.header-icon-link:hover {\n  opacity: 0.6;\n}\n\n.header-github-link:before {\n  content: '';\n  width: 24px;\n  height: 24px;\n  display: flex;\n  background: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E\")\n    no-repeat;\n}\n\nhtml[data-theme='dark'] .header-github-link:before {\n  background: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E\")\n    no-repeat;\n}\n\n"
  },
  {
    "path": "website/src/pages/index.js",
    "content": "import React from 'react';\nimport clsx from 'clsx';\nimport Link from '@docusaurus/Link';\nimport useDocusaurusContext from '@docusaurus/useDocusaurusContext';\nimport Layout from '@theme/Layout';\nimport HomepageFeatures from '@site/src/components/HomepageFeatures';\n\nimport styles from './index.module.css';\n\nfunction HomepageHeader() {\n  const { siteConfig } = useDocusaurusContext();\n  return (\n    <header className={clsx('hero hero--primary', styles.heroBanner)}>\n      <div className=\"container\">\n        <div className={styles.headerContent}>\n          <div className={styles.imageContainer}>\n            <img\n              height=\"200px\"\n              className={styles.heroImg}\n              src=\"img/logo.svg\"\n            />\n          </div>\n          <div className={styles.textContainer}>\n            <h1 className=\"hero__title\">{siteConfig.title}</h1>\n            <p className=\"hero__subtitle\">{siteConfig.tagline}</p>\n            <div className={styles.buttons}>\n              <Link\n                className=\"button button--secondary button--lg\"\n                to=\"/docs/category/quick-start\"\n              >\n                Quick Start\n              </Link>\n            </div>\n          </div>\n        </div>\n      </div>\n    </header>\n  );\n}\n\n\nexport default function Home() {\n  const {siteConfig} = useDocusaurusContext();\n  return (\n    <Layout\n      title={`${siteConfig.title}`}\n      description=\"🐵 HTTP mock server, useful to stub services and simulate dynamic API responses, leveraging ASP.NET Core features, built-in fake data generation and pure C# scripting\">\n      <HomepageHeader />\n      <main>\n        <HomepageFeatures />\n      </main>\n    </Layout>\n  );\n}\n"
  },
  {
    "path": "website/src/pages/index.module.css",
    "content": "/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 4rem 0;\n  text-align: left;\n  position: relative;\n  overflow: hidden;\n\n  background-image: url(\"palm-tree.svg\");\n  background-repeat: repeat-x;  \n}\n\n@media screen and (max-width: 996px) {\n  .heroBanner {\n    padding: 2rem;\n  }\n}\n\n.buttons {\n  display: flex;\n  align-items: left ;\n  justify-content: left;\n}\n\n.headerContent {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n}\n\n.imageContainer {\n  float: left;\n  margin-right: 40px;\n}\n\n.heroImg {\n  display: block;\n}"
  },
  {
    "path": "website/src/pages/videos.js",
    "content": "import React from 'react';\nimport Layout from '@theme/Layout';\nimport useDocusaurusContext from '@docusaurus/useDocusaurusContext';\nimport styles from './videos.module.css';\nimport ReactPlayer from 'react-player/youtube'\n\nexport default function Videos() {\n  const context = useDocusaurusContext();\n  const siteConfig = context.siteConfig;\n  return (\n    <Layout\n      title={`${siteConfig.title} Videos`}\n      description=\"A collection of Mockaco videos\">\n      <header>\n        <div className={styles.container}>\n          <div className=\"row\">\n            <div>\n              <h1 className=\"hero__title\">Mockaco Videos</h1>\n              <p className=\"hero__subtitle\">Videos showing some Mockaco features</p>\n            </div>\n          </div>\n        </div>\n      </header>\n      <main>\n        <div className={styles.container}>\n            <div className=\"row\">\n                <div className={styles.videoContainer}>\n                    <ReactPlayer url='https://www.youtube.com/watch?v=QBnXCgZFzM0' controls={true} />\n                </div>\n            </div>\n        </div>\n      </main>\n    </Layout>\n  );\n}"
  },
  {
    "path": "website/src/pages/videos.module.css",
    "content": ".container {\n    margin: 32px\n}\n\n.videoContainer {\n    width: 100%;\n    margin: 0;\n}\n\n.videosTitle {\n    margin-top: 30px;\n}"
  },
  {
    "path": "website/static/.nojekyll",
    "content": ""
  }
]